Go类型断言转换

I can convert an int to a float64 like this:

var a int = 10
var b float64 = float64(a)

With regards to type assertions, Effective Go states: 'The type must either be the concrete type held by the interface, or a second interface type that the value can be converted to.'

With that in mind, why does the following fail:

func foo(a interface{}) {
    fmt.Println(a.(float64))
}

func main() {
    var a int = 10
    foo(a)
}

This causes a panic: interface conversion: interface is int, not float64.

Note that the Go Spec says:

'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.'

Which does contradict the Effective Go statement but seems more in line with what I see.

This sentence in Effective Go seems indeed to be confusing. It looks like the author was thinking about structs at that time.

The chapter on assertions in the specification is much clearer :

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.

More precisely, if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T. In this case, T must implement the (interface) type of x; otherwise the type assertion is invalid since it is not possible for x to store a value of type T. If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.

The fact you can convert your int to a float (and the reverse) doesn't at all mean you can assert they're the same type.

The type must either be the concrete type held by the interface, or a second interface type that the value can be converted to

This basically explains the following:

package main

import "fmt"

type Stringer interface {
    String()
}

type Byter interface {
    Bytes()
}

type Stringbyter interface {
    Stringer
    Byter
}

type Polymorphic float64

func (p *Polymorphic) String() {}

func (p *Polymorphic) Bytes() {}

func main() {
    i := interface{}(new(Polymorphic))
    if _, ok := i.(Stringer); ok {
        fmt.Println("i can be asserted to Stringer")
    }
    if _, ok := i.(Byter); ok {
        fmt.Println("i can be asserted to Byter")
    }
    if _, ok := i.(Stringbyter); ok {
        fmt.Println("i can be asserted to Stringbyter")
    }
    if _, ok := i.(*Polymorphic); ok {
        fmt.Println("i can be asserted to *Polymorphic")
    }
    if _, ok := i.(int); ok {
        fmt.Println("i can be asserted to int") // Never runs
    }
}

The assertion to int fails because it's a concrete type (as opposed to interface type) which is not *Polymorphic itself.

You can only type assert from interface type to underlying type. In this case int. Then you use type conversion from int to float64