How can I check if a value implements an interface dynamically?

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

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(&quot;%T implements %s\n&quot;, h, rt)
	}
}

func worker(s Hello) {
	//...
	check(s, (*Person)(nil))
	//...
}

Note that you need to use (*Person)(nil), (Person)(nil) will not work.

https://play.golang.org/p/2Bhy49SSol9

huangapple
  • 本文由 发表于 2021年7月23日 18:27:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/68497744.html
匿名

发表评论

匿名网友

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

确定