为什么我不能将*Struct分配给*Interface?

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

Why can't I assign a *Struct to an *Interface?

问题

我只是在通过Go教程学习,对指针和接口感到困惑。为什么这段Go代码不能编译?

  1. package main
  2. type Interface interface {}
  3. type Struct struct {}
  4. func main() {
  5. var ps *Struct
  6. var pi *Interface
  7. pi = ps
  8. _, _ = pi, ps
  9. }

也就是说,如果Struct是一个Interface,为什么*Struct不是*Interface

我得到的错误信息是:

  1. prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
  2. *Interface is pointer to interface, not interface
英文:

I'm just working through the Go tour, and I'm confused about pointers and interfaces. Why doesn't this Go code compile?

  1. package main
  2. type Interface interface {}
  3. type Struct struct {}
  4. func main() {
  5. var ps *Struct
  6. var pi *Interface
  7. pi = ps
  8. _, _ = pi, ps
  9. }

i.e. if Struct is an Interface, why wouldn't a *Struct be a *Interface?

The error message I get is:

  1. prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
  2. *Interface is pointer to interface, not interface

答案1

得分: 223

当你有一个实现接口的结构体时,指向该结构体的指针也会自动实现该接口。这就是为什么在函数的原型中从不使用*SomeInterface,因为这对SomeInterface没有任何增加,并且在变量声明中也不需要这样的类型(参见这个相关问题)。

接口值不是具体结构体的值(因为它具有可变大小,这是不可能的),而是一种指针(更准确地说是指向结构体和类型的指针)。Russ Cox在这里描述得非常准确:

> 接口值表示为一个两个字的对,其中一个字是指向存储在接口中的类型信息的指针,另一个字是指向关联数据的指针。

为什么我不能将*Struct分配给*Interface?

这就是为什么Interface而不是*Interface是持有实现Interface的结构体的指针的正确类型。

所以你只需要使用

  1. var pi Interface
英文:

When you have a struct implementing an interface, a pointer to that struct implements automatically that interface too. That's why you never have *SomeInterface in the prototype of functions, as this wouldn't add anything to SomeInterface, and you don't need such a type in variable declaration (see this related question).

An interface value isn't the value of the concrete struct (as it has a variable size, this wouldn't be possible), but it's a kind of pointer (to be more precise a pointer to the struct and a pointer to the type). Russ Cox describes it exactly here :

> Interface values are represented as a two-word pair giving a pointer
> to information about the type stored in the interface and a pointer to
> the associated data.

为什么我不能将*Struct分配给*Interface?

This is why Interface, and not *Interface is the correct type to hold a pointer to a struct implementing Interface.

So you must simply use

  1. var pi Interface

答案2

得分: 10

这可能是你的意思:

  1. package main
  2. type Interface interface{}
  3. type Struct struct{}
  4. func main() {
  5. var ps *Struct
  6. var pi *Interface
  7. pi = new(Interface)
  8. *pi = ps
  9. _, _ = pi, ps
  10. }

编译正常。另请参见这里

英文:

This is perhaps what you meant:

  1. package main
  2. type Interface interface{}
  3. type Struct struct{}
  4. func main() {
  5. var ps *Struct
  6. var pi *Interface
  7. pi = new(Interface)
  8. *pi = ps
  9. _, _ = pi, ps
  10. }

Compiles OK. See also here.

答案3

得分: 0

这是一种非常简单的将结构体分配给接口的方法:

  1. package main
  2. type Interface interface{}
  3. type Struct struct{}
  4. func main() {
  5. ps := new(Struct)
  6. pi := Interface(ps)
  7. _, _ = pi, ps
  8. }

https://play.golang.org/p/BRTaTA5AG0S

英文:

Here's a very simple way of assigning a struct to an interface:

  1. package main
  2. type Interface interface{}
  3. type Struct struct{}
  4. func main() {
  5. ps := new(Struct)
  6. pi := Interface(ps)
  7. _, _ = pi, ps
  8. }

https://play.golang.org/p/BRTaTA5AG0S

答案4

得分: 0

我使用了以下的interface{}的方式,虽然我只是使用eventsI interface{}作为参数,但我仍然可以发送一个结构体指针,如下所示。

  1. func Wait(seconds float64) *WaitEvent {
  2. return WaitEventCreate(seconds)
  3. }

main.go

  1. var introScene = []interface{}{
  2. storyboard.Wait(5),
  3. storyboard.Wait(2),
  4. }
  5. var storyboardI = storyboard.Create(stack, introScene)
  6. stack.Push(&storyboardI)

现在在storyboard.go文件的Create函数中

  1. type Storyboard struct {
  2. Stack *gui.StateStack
  3. Events []interface{} //always keep as last args
  4. }
  5. func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
  6. sb := Storyboard{
  7. Stack: stack,
  8. }
  9. if eventsI != nil {
  10. events := reflect.ValueOf(eventsI)
  11. if events.Len() > 0 {
  12. sb.Events = make([]interface{}, events.Len())
  13. for i := 0; i < events.Len(); i++ {
  14. sb.Events[i] = events.Index(i).Interface()
  15. }
  16. }
  17. }
  18. return sb
  19. }

如上所示,Storyboard.go只消耗Events []interface{},但实际上我发送的是一个结构体指针,它可以正常工作。

另一个更多的例子在这里

英文:

Im using the following way of interface{} while im just consuming eventsI interface{} as arguments, im still able to send a Struct Pointers as you can see below.

  1. func Wait(seconds float64) *WaitEvent {
  2. return WaitEventCreate(seconds)
  3. }

main.go

  1. var introScene = []interface{}{
  2. storyboard.Wait(5),
  3. storyboard.Wait(2),
  4. }
  5. var storyboardI = storyboard.Create(stack, introScene)
  6. stack.Push(&amp;storyboardI)

Now inside storyboard.go file Create function

  1. type Storyboard struct {
  2. Stack *gui.StateStack
  3. Events []interface{} //always keep as last args
  4. }
  5. func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
  6. sb := Storyboard{
  7. Stack: stack,
  8. }
  9. if eventsI != nil {
  10. events := reflect.ValueOf(eventsI)
  11. if events.Len() &gt; 0 {
  12. sb.Events = make([]interface{}, events.Len())
  13. for i := 0; i &lt; events.Len(); i++ {
  14. sb.Events[i] = events.Index(i).Interface()
  15. }
  16. }
  17. }
  18. return sb
  19. }

As you can see above the Storyboard.go is consuming just Events []interface{} but in-fact Im sending is a Struct pointer and it works fine.

another more example here

huangapple
  • 本文由 发表于 2012年11月22日 18:55:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/13511203.html
匿名

发表评论

匿名网友

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

确定