【问题标题】:How can I check if a value implements an interface dynamically?如何检查值是否动态实现接口?
【发布时间】:2021-09-30 11:55:02
【问题描述】:

假设我有一个名为 Hello 的接口,例如:

type Hello interface {
   Hi() string
}

我想编写一个函数来获取Hello 和任何接口n 并在Hello 也实现n 接口时执行某些操作,例如:

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 
  }
}

check函数如何实现?

【问题讨论】:

    标签: go reflection


    【解决方案1】:

    使用反射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)because

    如果 i 是 nil 接口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)
    }
    

    游乐场: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 游乐场:https://go2goplay.golang.org/p/HIBn3IYW13W

    【讨论】:

      【解决方案2】:

      是的,您可以为此使用反射。

      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))
          //...
      }
      

      注意你需要使用(*Person)(nil)(Person)(nil)是不行的。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-19
        • 1970-01-01
        • 2015-03-04
        • 2012-03-25
        • 2018-11-16
        • 1970-01-01
        • 2016-09-29
        • 1970-01-01
        相关资源
        最近更新 更多