Go类型断言转换

huangapple go评论74阅读模式
英文:

Go type assertion conversion

问题

我可以这样将int转换为float64:

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

关于类型断言,Effective Go中指出:“类型必须是接口所持有的具体类型,或者是该值可以转换为的第二个接口类型。”

考虑到这一点,为什么以下代码会失败:

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

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

这会导致panic: interface conversion: interface is int, not float64

请注意,Go规范中说:

“对于一个接口类型的表达式x和类型T,主表达式

x.(T)

断言x不是nil,并且存储在x中的值是类型T。”

这与Effective 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.

答案1

得分: 9

这句话在Effective Go中似乎确实令人困惑。看起来作者当时在考虑结构体。

在规范中关于断言的章节更清晰:

对于一个接口类型的表达式x和类型T,主要表达式

x.(T)断言x不是nil,并且存储在x中的值是类型T。x.(T)的表示法被称为类型断言。

更准确地说,如果T不是接口类型,x.(T)断言x的动态类型与类型T相同。在这种情况下,T必须实现x的(接口)类型;否则,类型断言是无效的,因为x不可能存储类型T的值。如果T是接口类型,x.(T)断言x的动态类型实现了接口T。

事实上,你可以将int转换为float(反之亦然),并不意味着你可以断言它们是相同的类型。

英文:

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.

答案2

得分: 9

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.

英文:

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

答案3

得分: 0

你只能从接口类型转换为底层类型使用assert。在这种情况下是int。然后你使用类型转换从int转换为float64

英文:

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

huangapple
  • 本文由 发表于 2013年5月30日 21:21:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/16837375.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定