英文:
How can I check if a value implements an interface dynamically?
问题
你可以使用反射来实现check
函数。以下是一个使用反射的示例实现:
import "reflect"
func check(h Hello, n interface{}) {
nType := reflect.TypeOf(n)
if reflect.TypeOf(h).Implements(nType) {
// do something
}
}
在这个实现中,我们首先使用reflect.TypeOf
获取n
的类型。然后,我们使用reflect.TypeOf(h).Implements(nType)
来检查h
是否实现了n
的接口。如果是,则可以执行相应的操作。
请注意,使用反射可能会导致性能下降,因此请谨慎使用。如果可能的话,最好使用静态类型检查来实现这样的功能。
英文:
Assuming I have an interface called Hello
like:
type Hello interface {
Hi() string
}
I want to write a function that gets Hello
and any interface n
and does something if Hello
also implements n
interface, like:
type Person interface {
Name() int
}
type Animal interface {
Leg() int
}
type hello struct{}
func (h hello) Hi() string {
return "hello!"
}
func (h hello) Leg() int {
return 4
}
func worker() {
h := hello{}
// Doesn't match
check(h,(Person)(nil))
// Matches
check(h,(Animal)(nil))
}
func check(h Hello, n interface{}) {
// of course this doesn't work, should I use reflection, if so how?
if _,ok := h.(n); ok {
// do something
}
}
How to implement the check
function?
答案1
得分: 8
使用反射Type.Implements
。
func check(n interface{}) bool {
i := reflect.TypeOf(new(Hello)).Elem()
return reflect.TypeOf(n).Implements(i)
}
如果你想要使用的接口已知,你可以直接使用new(Hello)
或(*Hello)(nil)
来实例化它,而不需要向函数传递额外的参数。
你不能使用(Hello)(nil)
因为:
如果
i
是一个空接口值,TypeOf
返回nil
。
否则,如果参考接口也是动态的,你可以将其作为参数传递。原理是相同的:
func main() {
fmt.Println(check(new(Hello), new(Person))) // false
}
func check(i interface{}, n interface{}) bool {
ti := reflect.TypeOf(i).Elem()
return reflect.TypeOf(n).Implements(ti)
}
Playground: https://play.golang.org/p/GYDcxtIobKc
在Go 1.18(2022年初)添加泛型到语言之后,你将能够编写一个通用函数,使用type assertion:
如果
T
是一个接口类型,x.(T)
断言x
的动态类型实现了接口T
。
它将如下所示:
func check[T any](i T, n interface{}) bool {
_, ok := n.(T)
return ok
}
Go2 Playground: https://go2goplay.golang.org/p/HIBn3IYW13W
英文:
Use reflection Type.Implements
func check(n interface{}) bool {
i := reflect.TypeOf(new(Hello)).Elem()
return reflect.TypeOf(n).Implements(i)
}
If the interface you want to use as reference is known, you can just instantiate it with new(Hello)
or (*Hello)(nil)
without passing an extra argument to the function.
You can't use (Hello)(nil)
because:
> If i is a nil interface value, TypeOf
returns nil
.
Otherwise if the reference interface is also dynamic, you can pass it as an argument. The principle is the same:
func main() {
fmt.Println(check(new(Hello), new(Person))) // false
}
func check(i interface{}, n interface{}) bool {
ti := reflect.TypeOf(i).Elem()
return reflect.TypeOf(n).Implements(ti)
}
Playground: https://play.golang.org/p/GYDcxtIobKc
<hr>
After generics will be added to the language in Go 1.18 (early 2022), you will be able to write a generic function for this that uses a type assertion:
> If T
is an interface type, x.(T)
asserts that the dynamic type of x
implements the interface T
.
It would look like:
func check[T any](i T, n interface{}) bool {
_, ok := n.(T)
return ok
}
Go2 Playground: https://go2goplay.golang.org/p/HIBn3IYW13W
答案2
得分: 2
是的,你可以使用反射来实现这个功能。
func check(h Hello, n interface{}) {
rt := reflect.TypeOf(n).Elem()
if reflect.TypeOf(h).Implements(rt) {
fmt.Printf("%T 实现了 %s\n", h, rt)
}
}
func worker(s Hello) {
//...
check(s, (*Person)(nil))
//...
}
请注意,你需要使用(*Person)(nil)
,(Person)(nil)
是不起作用的。
https://play.golang.org/p/2Bhy49SSol9
英文:
Yes you can use reflection for this.
func check(h Hello, n interface{}) {
rt := reflect.TypeOf(n).Elem()
if reflect.TypeOf(h).Implements(rt) {
fmt.Printf("%T implements %s\n", h, rt)
}
}
func worker(s Hello) {
//...
check(s, (*Person)(nil))
//...
}
Note that you need to use (*Person)(nil)
, (Person)(nil)
will not work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论