英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论