如何获取接口{}的指针以键入检查接口实现

sha*_*ner 3 pointers interface go

所以我基本上试图找到最好的方法来达到这样的目的:

package main

import "fmt"

type SomeStruct struct {
}

type SomeInterface interface {
  SomeMethodWhichNeedsAPointerReceiver() string
}

func (s *SomeStruct) SomeMethodWhichNeedsAPointerReceiver() string {
  return "Well, believe me, I wrote something"
}

func Run(s interface{}) {
  // how can I cast s to a pointer here?
  casted, ok := (s).(SomeInterface)
  if ok {
    fmt.Println("Awesome: " + casted.SomeMethodWhichNeedsAPointerReceiver())
    return 
  }

  fmt.Println("Fail :(")
}

func SomeThirdPartyMethod() interface{} {
  return SomeStruct{}
}

func main() {
  x := SomeThirdPartyMethod()
  Run(x)
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,在Run方法的类型转换中.我基本上只知道它是interface {}类型,现在我需要调用一个接口方法,它有一个指针接收器.

我目前唯一的解决方案是动态构造一个带有反射的切片,将该元素设置为切片,然后使其成为可压缩的.

这真的是找到解决方案的唯一可能性吗?

播放链接

icz*_*cza 6

在Go中,接口只是一组方法(规范:接口类型).

接口不指定接收器是否为指针.在Go中实现接口是隐含的:没有意图声明.

您需要阅读并理解方法集.引用它的一个重要部分:

任何其他类型的方法集T包含用接收器类型声明的所有方法T.设置相应的方法指针类型 *T是一组与接收器声明的所有方法*TT(即,它也包含的方法集T).

如果其类型的方法集是接口的超集(接口类型的方法)(其可以是或可以不是一个指针)实现的接口.

在你的例子中:

func (s *SomeStruct) SomeMethodWhichNeedsAPointerReceiver() string{}
Run Code Online (Sandbox Code Playgroud)

SomeMethodWhichNeedsAPointerReceiver()有一个指针接收器,所以type的值SomeStruct不会有这个方法,但是type的值*SomeStruct会.

因此,作为一个后果类型的值SomeStruct 不会实现你的SomeInterface接口(因为它没有一个SomeMethodWhichNeedsAPointerReceiver()方法),但*SomeStruct 确实实现你的SomeInterface,因为它的方法集包含SomeMethodWhichNeedsAPointerReceiver()方法.

由于您创建并使用简单SomeStruct值(而不是指向它的指针),因此类型断言将失败.

如果您使用过a *SomeStruct,那么类型断言就会成功.

修改你的SomeThirdPartyMethod()函数来创建并返回一个*SomeStruct(一个指针),它将按你的预期工作:

func SomeThirdPartyMethod() interface{} {
    return &SomeStruct{}
}
Run Code Online (Sandbox Code Playgroud)

或作为替代方案:

func SomeThirdPartyMethod() interface{} {
    return new(SomeStruct)
}
Run Code Online (Sandbox Code Playgroud)

Go Playground尝试一下.

如果你不能修改 SomeThirdPartyMethod()

如果你不能修改这个SomeThirdPartyMethod()函数:首先,它是否意图/要求它返回一个实现的值SomeStruct?如果是这样,那么它的当前实现是错误的,你可以期望它返回一个实现的值,SomeStruct而不必取消引用它(为了获得实现的值SomeStruct).

在这种特定情况下,您还可以尝试为SomeStruct自己键入断言:

if ss, ok := s.(SomeStruct); ok {
    fmt.Println(ss.SomeMethodWhichNeedsAPointerReceiver())
}
Run Code Online (Sandbox Code Playgroud)

调用ss.SomeMethodWhichNeedsAPointerReceiver()将自动取消引用ss以获取其地址(这将是用于调用SomeMethodWhichNeedsAPointerReceiver()方法的指针接收器值).