如何获取interface {}的指针以键入检查接口的实现
So I'm basically trying to find out the best way to get to something like this:
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)
}
My problem here is, at the typecast in the Run method. I basically only know that it is of type interface{} and now I need to call an interface method, which has a pointer receiver.
My only solution at the moment is to dynamically construct a slice with reflection, set the element into the slice, and than make it adressable.
Is this really the only possibility to find a solution?
因此,我基本上是在尝试找到达到以下目标的最佳方法: p> \ n
包main
import“ fmt”
type SomeStruct struct {
}
type SomeInterface接口{
SomeMethodWhichNeedsAPointerReceiver()string
}
func(s * SomeStruct)SomeMethodWhichNeedsAPointerReceiver()字符串{
返回“好吧,相信我,我写了一些东西”
}
func Run(s interface {}){
//如何将s强制转换为指针?
强制转换,确定:=(s)。(SomeInterface)
如果确定{
fmt.Println(“ Awesome:” + casted.SomeMethodWhichNeedsAPointerReceiver())
返回
}
fmt.Println( “失败:(”)
}
func SomeThirdPartyMethod()接口{} {
返回SomeStruct {}
}
func main(){
x:= SomeThirdPartyMethod()
Run(x)
}
code> pre>
我的问题是在Run方法的类型转换中。
我基本上只知道它的类型为interface {},现在我需要
调用具有指针接收器的接口方法。
目前,我唯一的解决方案是使用反射动态构造一个切片,将元素设置为切片,然后对其进行寻址。 p>
这真的是找到解决方案的唯一可能性吗? p>
播放链接 p>
DIV>
The best solution would indeed be to return a pointer from SomeThirdPartyMethod
. But if this is not possible, you can construct a pointer to that value using 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
}
Working example: http://play.golang.org/p/JYJT8mRxWN
In Go, an interface is just a set of methods (spec: Interface types).
The interface does not specify whether receivers are pointers or not. Implementing an interface in Go is implicit: there is no declaration of intent.
You need to read and understand Method sets. Quoting an important part of it:
The method set of any other type
T
consists of all methods declared with receiver typeT
. The method set of the corresponding pointer type*T
is the set of all methods declared with receiver*T
orT
(that is, it also contains the method set ofT
).
A value (which may or may not be a pointer) implements an interface if the method set of its type is a superset of the interface (the methods of the interface type).
In your example:
func (s *SomeStruct) SomeMethodWhichNeedsAPointerReceiver() string{}
SomeMethodWhichNeedsAPointerReceiver()
has a pointer receiver, so a value of type SomeStruct
will not have this method, but a value of type *SomeStruct
will.
So as a consequence a value of type SomeStruct
does not implement your SomeInterface
interface (because it does not have a SomeMethodWhichNeedsAPointerReceiver()
method), but *SomeStruct
does implement your SomeInterface
because its method set contains the SomeMethodWhichNeedsAPointerReceiver()
method.
Since you create and use a simple SomeStruct
value (and not a pointer to it), the type assertion will fail.
Should you have used a *SomeStruct
, the type assertion would have succeeded.
Modify your SomeThirdPartyMethod()
function to create and return a *SomeStruct
(a pointer) and it will work as you expect it:
func SomeThirdPartyMethod() interface{} {
return &SomeStruct{}
}
Or as an alternative:
func SomeThirdPartyMethod() interface{} {
return new(SomeStruct)
}
Try it on the Go Playground.
If you can't modify SomeThirdPartyMethod()
If you can't modify the SomeThirdPartyMethod()
function: first of all, is it intended/required that it returns a value which implements SomeStruct
? If so, then its current implementation is wrong, and you can expect it to return a value which does implement SomeStruct
without you having to dereference it (in order to gain a value which implements SomeStruct
).
In this specific case you can also try type assertion for SomeStruct
itself:
if ss, ok := s.(SomeStruct); ok {
fmt.Println(ss.SomeMethodWhichNeedsAPointerReceiver())
}
Calling ss.SomeMethodWhichNeedsAPointerReceiver()
will automatically dereference ss
to take its address (which will be the pointer receiver value for calling the SomeMethodWhichNeedsAPointerReceiver()
method).