将接受接口的函数的结构体传递给它。

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

Pass struct for function that accepts a interface

问题

我有以下代码:

package main


type MyInterface interface {
    Test()
}

type MyType struct {
    
}
func (m MyType) Test(){}

func AcceptInterface(i *MyInterface){
}

func main() {

    object := &MyType{}
    AcceptInterface(object)
}

我原本期望这段代码能够正常工作,因为MyType实现了MyInterface接口,但是我得到了以下错误信息:

无法将object(类型为*MyType)作为AcceptInterface的参数,因为*MyInterface是指向接口的指针,而不是接口本身。

我尝试使用类型断言:object.(MyInterface),但也不起作用。

我该如何解决这个问题?

英文:

I have the following code:

package main


type MyInterface interface {
	Test()
}

type MyType struct {
	
}
func (m MyType) Test(){}

func AcceptInterface(i *MyInterface){
}

func main() {

	object := &MyType{}
	AcceptInterface(object)
}

I was expecting this to work, because MyType implements MyInterface, but I get:

> cannot use object (type *MyType) as type *MyInterface in argument to
> AcceptInterface: *MyInterface is pointer to interface, not interface

I tried doing type assertion: object.(MyInterface), but that doesn't work either.

How can I accomplish this?

答案1

得分: 15

根据错误提示,它说:

> 无法将对象(类型 *MyType)作为参数传递给 AcceptInterface 函数中的 *MyInterface 类型:*MyInterface 是指向接口的指针,而不是接口本身。

这意味着它期望的是一个 interface 值,而不是一个指针。

如果你在代码中将指针改为值(删除 &*),程序将不会出现错误:

package main

type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

func AcceptInterface(i MyInterface){
}

func main() {

    object := MyType{}
    AcceptInterface(object)
}

在 Go Playground 上运行

编辑 1

如果你仍然想要使用指针作为参数,有两个关键的 Go 语言部分需要注意:

  1. 根据Go 语言规范,关于什么样的变量适合一个实例:

    > 接口类型的变量可以存储任何具有方法集的类型的值,该方法集是接口的任何超集。

  2. 根据Go 语言规范,关于指针自动解引用:

    > 与选择器一样,使用指针引用一个具有值接收器的非接口方法将自动解引用该指针:pt.Mv 等同于 (*pt).Mv [和] 与方法调用一样,使用可寻址值引用具有指针接收器的非接口方法将自动取该值的地址:t.Mp 等同于 (&t).Mp.

这两点很重要,因为它们结合起来解释了_指针变量仍然可以适合实例_。这是因为指针的方法集会被 Go 编译器自动解引用_(并且由于它所引用的变量可以适合一个实例,指针也可以适合)_!

实际上,这意味着为了判断一个指针是否适合一个实例,你必须将实例声明为_值_,将指针声明为_指针_。

如果你运行以下代码:

package main

type MyInterface interface {
    Test()
}

type MyType struct {
}

func (m MyType) Test() {}

func AcceptInterface(i MyInterface) {
}

func main() {
    object := &MyType{}
    AcceptInterface(object)
}

在 Go Playground 上运行

你将看到没有错误!注意 object 声明中有一个 &,但是 i 声明中没有 *

英文:

As the error says,

> cannot use object (type *MyType) as type *MyInterface in argument to AcceptInterface: *MyInterface is pointer to interface, not interface

This means that it is expecting an interface value, not a pointer.

If you change the pointers to values in your code (by removing the & and *), the program will run with no errors:

package main


type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

func AcceptInterface(i MyInterface){
}

func main() {

    object := MyType{}
    AcceptInterface(object)
}

Play it

Edit 1

If you still want to use a pointer as an argument, there are two important parts of the Go language to note

  1. From the Go Spec on what exacly is a variable that fits an instance:

    > A variable of interface type can store a value of any type with a method set that is any superset of the interface.

  2. From the Go Spec on what pointers being automatically dereferenced:

    > As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv [and] as with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.

Those two points are important, because when combined they explain that pointers to variables can still fit instances. This is because the pointer's method set is automatically dereferenced by the Go compiler (and since the variable it is referencing can fit an instance, the pointer can, too)!

In action, this means that in order to see if a pointer fits an instance, you have to declare the instance as a value and the pointer as a pointer.

If you run this code:

package main

type MyInterface interface {
    Test()
}

type MyType struct {
}

func (m MyType) Test() {}

func AcceptInterface(i MyInterface) {
}

func main() {
    object := &MyType{}
    AcceptInterface(object)
}

Play it

you will see that there are no errors! Notice how there is an & in the object declaration, but no * in the i declaration?

答案2

得分: 0

type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

// 注意:这意味着 `MyType` 实现了接口 `MyInterface`,而不是 `MyType*`。

你可以使用

func (m *MyType) Test(){}  // 注意这里

func AcceptInterface(i *MyInterface){
}

func main() {

    object := &MyType{}
    AcceptInterface(object)
}
英文:
type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

Note: it means that MyType implemts the interface MyInterface, not MyType*.

You can use:

func (m *MyType) Test(){}  //Notice here

func AcceptInterface(i *MyInterface){
}

func main() {

    object := &MyType{}
    AcceptInterface(object)
}

答案3

得分: 0

如果你想传递一个指向接口的指针,请使用显式类型转换:

func main() {
    var object MyInterface = MyType{}
    AcceptInterface(&object)
}

我不建议使用指针接口,因为你需要编写类似(*i).Test()这样的代码来调用接口指针的方法。编译器会自动对结构体指针进行解引用,但对于接口指针则不会这样做。

英文:

Use explicit typing if you want to pass a pointer to interface:

func main() {
	var object MyInterface = MyType{}
	AcceptInterface(&object)
}

I would not recommend using pointer interfaces as you would need to write code like (*i).Test() to call the interface pointer methods. The compiler do auto dereferencing for struct pointers, not so for interface pointers.

huangapple
  • 本文由 发表于 2017年1月17日 09:26:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/41687665.html
匿名

发表评论

匿名网友

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

确定