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

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

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

问题

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

package main

type Interface interface {}

type Struct struct {}

func main() {
	var ps *Struct
	var pi *Interface
	pi = ps
	
	_, _ = pi, ps
}

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

我得到的错误信息是:

prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
	    *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?

package main

type Interface interface {}

type Struct struct {}

func main() {
	var ps *Struct
	var pi *Interface
	pi = ps
	
	_, _ = pi, ps
}

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

The error message I get is:

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

答案1

得分: 223

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

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

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

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

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

所以你只需要使用

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

var pi Interface

答案2

得分: 10

这可能是你的意思:

package main

type Interface interface{}

type Struct struct{}

func main() {
        var ps *Struct
        var pi *Interface
        pi = new(Interface)
        *pi = ps

        _, _ = pi, ps
}

编译正常。另请参见这里

英文:

This is perhaps what you meant:

package main

type Interface interface{}

type Struct struct{}

func main() {
        var ps *Struct
        var pi *Interface
        pi = new(Interface)
        *pi = ps

        _, _ = pi, ps
}

Compiles OK. See also here.

答案3

得分: 0

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

package main

type Interface interface{}

type Struct struct{}

func main() {
    ps := new(Struct)
    pi := Interface(ps)

    _, _ = pi, ps
}

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

英文:

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

package main

type Interface interface{}

type Struct struct{}

func main() {
    ps := new(Struct)
    pi := Interface(ps)

    _, _ = pi, ps
}

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

答案4

得分: 0

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

func Wait(seconds float64) *WaitEvent {
	return WaitEventCreate(seconds)
}

main.go

var introScene = []interface{}{
		storyboard.Wait(5),
		storyboard.Wait(2),
	}

	var storyboardI = storyboard.Create(stack, introScene)
	stack.Push(&storyboardI)

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

type Storyboard struct {
	Stack  *gui.StateStack
	Events []interface{} //always keep as last args
}

func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
	sb := Storyboard{
		Stack: stack,
	}

	if eventsI != nil {
		events := reflect.ValueOf(eventsI)
		if events.Len() > 0 {
			sb.Events = make([]interface{}, events.Len())
			for i := 0; i < events.Len(); i++ {
				sb.Events[i] = events.Index(i).Interface()
			}
		}
	}

	return sb
}

如上所示,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.

func Wait(seconds float64) *WaitEvent {
	return WaitEventCreate(seconds)
}

main.go

var introScene = []interface{}{
		storyboard.Wait(5),
		storyboard.Wait(2),
	}

	var storyboardI = storyboard.Create(stack, introScene)
	stack.Push(&amp;storyboardI)

Now inside storyboard.go file Create function

type Storyboard struct {
	Stack  *gui.StateStack
	Events []interface{} //always keep as last args
}

func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
	sb := Storyboard{
		Stack: stack,
	}

	if eventsI != nil {
		events := reflect.ValueOf(eventsI)
		if events.Len() &gt; 0 {
			sb.Events = make([]interface{}, events.Len())
			for i := 0; i &lt; events.Len(); i++ {
				sb.Events[i] = events.Index(i).Interface()
			}
		}
	}

	return sb
}

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:

确定