未捕获类型断言中的第二个返回值会导致运行时恐慌[关闭]

Below code causes runtime panic on second Println if assertion fails and second value "OK" is not provided for assignment for return value. however, if the second value is provided runtime panic does not occur. How not assigning return value can cause the panic? is there any good resource to learn about panics in Go?

var i interface{} = "hello" 

    f, ok := i.(float64) //  no runtime panic
    fmt.Println(f, ok)

    f = i.(float64) // panic
    fmt.Println(f)

Update 1: To make the question more clear. I wanted to know how panic occurs at runtime when the second return value is not caught 'ok' and panic does not occur when the second return value is caught (f is assigned to zero value and ok is false)

Update 2: From the discussion I understood, assigning two return values handles the runtime panic, in short, it acts as a safeguard. Marking the answer as correct.

This is how type assertions are defined to work, nothing shocking about that.

Language Spec: Type assertions:

For an expression x of interface type and a type T, the primary expression

x.(T)

asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.

[...] If the type assertion holds, the value of the expression is the value stored in x and its type is T. If the type assertion is false, a run-time panic occurs.

[...] A type assertion used in an assignment or initialization of the special form

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok T1 = x.(T)

yields an additional untyped boolean value. The value of ok is true if the assertion holds. Otherwise it is false and the value of v is the zero value for type T. No run-time panic occurs in this case.

In your case i holds a dynamic value of type string, and yet you try to type-assert a value of float64 from it. So the type assertion is false, and per spec a run-time panic occurs. If you'd write i.(string) => this type assertion is true, so no run-time panic would occur in this case.

If you use the special form (assigning 2 return values), it will never panic, rather if type assertion does not hold, first value will be the zero value of the type you try to assert, second value will be an untyped boolean value false.

You can use an underscore for variables you don't need.

var i interface{} = "hello" 

    f, ok := i.(float64) //  no runtime panic
    fmt.Println(f, ok)

    f, _ = i.(float64) // panic
    fmt.Println(f)