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

时间:2015-04-20 09:38:06

标签: pointers go interface

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

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方法的类型转换中。 我基本上只知道它是interface {}类型,现在我需要 调用一个接口方法,它有一个指针接收器。

我目前唯一的解决方案是使用反射动态构造切片,将元素设置为切片,然后使其可以进行处理。

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

Play link

2 个答案:

答案 0 :(得分:6)

在Go中,界面只是一组方法(spec: Interface types)。

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

您需要阅读并理解Method sets。引用其中的一个重要部分:

  

任何其他类型T的方法集由声明为接收器类型T的所有methods组成。相应pointer type *T的方法集是使用receiver *TT声明的所有方法的集合(也就是说,它还包含{{1}的方法集}})。

(可能是也可能不是指针)如果其类型的方法集是接口的超集(接口类型的方法),则实现接口。

在你的例子中:

T

func (s *SomeStruct) SomeMethodWhichNeedsAPointerReceiver() string{} 有一个指针接收器,因此类型为SomeMethodWhichNeedsAPointerReceiver()的值不会有此方法,但类型为SomeStruct的值将为。

因此,*SomeStruct 类型的值不会实现您的SomeStruct接口(因为它没有SomeInterface方法),但{ {1}} 确实实施您的SomeMethodWhichNeedsAPointerReceiver(),因为其方法集包含*SomeStruct方法。

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

如果你使用了SomeMethodWhichNeedsAPointerReceiver(),那么类型断言就会成功。

修改您的SomeStruct函数以创建并返回*SomeStruct(指针),它将按预期工作:

SomeThirdPartyMethod()

或作为替代方案:

*SomeStruct

Go Playground上尝试。

如果您无法修改func SomeThirdPartyMethod() interface{} { return &SomeStruct{} }

如果你不能修改func SomeThirdPartyMethod() interface{} { return new(SomeStruct) } 函数:首先,它是否打算/要求它返回一个实现SomeThirdPartyMethod()的值?如果是这样,那么它的当前实现是错误的,你可以期望它返回一个实现SomeThirdPartyMethod()的值,而不必取消引用它(为了获得实现SomeStruct的值)。 / p>

在这种特定情况下,您还可以尝试为SomeStruct本身输入断言:

SomeStruct

调用SomeStruct将自动取消引用if ss, ok := s.(SomeStruct); ok { fmt.Println(ss.SomeMethodWhichNeedsAPointerReceiver()) } 以获取其地址(这将是用于调用ss.SomeMethodWhichNeedsAPointerReceiver()方法的指针接收器值。)

答案 1 :(得分:4)

最好的解决方案确实是从SomeThirdPartyMethod返回一个指针。但如果无法做到这一点,您可以使用reflection构建指向该值的指针:

v := reflect.Indirect(reflect.New(reflect.TypeOf(s)))
v.Set(reflect.ValueOf(s))
sp := v.Addr().Interface()
casted, ok = (sp).(SomeInterface)
if ok {
    fmt.Println("Good as well: " + casted.SomeMethodWhichNeedsAPointerReceiver())
    return
}

工作示例:http://play.golang.org/p/JYJT8mRxWN