如何获取接口的反射类型(reflect.Type)?

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

How to get the reflect.Type of an interface?

问题

为了确定一个给定的类型是否实现了一个接口,你需要使用反射包将一个 reflect.Type 传递给 reflect.Type.Implements()。那么如何获取这些类型之一呢?

举个例子,尝试获取一个未初始化的 error(接口)类型的类型是不起作用的(当你调用它的 Kind() 方法时会引发 panic)。

var err error
fmt.Printf("%#v\n", reflect.TypeOf(err).Kind())
英文:

In order to determine whether a given type implements an interface using the reflect package, you need to pass a reflect.Type to reflect.Type.Implements(). How do you get one of those types?

As an example, trying to get the type of an uninitialized error (interface) type does not work (it panics when you to call Kind() on it)

var err error
fmt.Printf("%#v\n", reflect.TypeOf(err).Kind())

答案1

得分: 55

像这样做:

var err error
t := reflect.TypeOf(&err).Elem()

或者一行代码:

t := reflect.TypeOf((*error)(nil)).Elem()
英文:

Do it like this:

var err error
t := reflect.TypeOf(&err).Elem()

Or in one line:

t := reflect.TypeOf((*error)(nil)).Elem()

答案2

得分: 13

即使Shaw的回答是正确的,但是很简洁。从reflect.TypeOf方法的文档中可以得到更多细节:

// 由于接口类型仅用于静态类型,一个常见的惯用法是通过使用*Foo值来找到接口类型Foo的反射类型。

writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()

fileType := reflect.TypeOf((*os.File)(nil)).Elem()
fmt.Println(fileType.Implements(writerType))

英文:

Even Shaws response is correct, but brief. Some more details from the reflect.TypeOf method documentation:

// As interface types are only used for static typing, a common idiom to find
// the reflection Type for an interface type Foo is to use a *Foo value.

writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()

fileType := reflect.TypeOf((*os.File)(nil)).Elem()
fmt.Println(fileType.Implements(writerType))

答案3

得分: -1

对于那些谷歌员工,我刚刚遇到了可怕的“scannable dest type interface {} with >1 columns (XX) in result”错误。

Evan Shaw的答案对我没有用。这是我解决它的方法。我也在使用lann/squirrel库,但你可以很容易地将其移除。

解决方案并不复杂,只需要知道反射调用的魔法组合。

me.GetSqlx()函数只是返回一个*sqlx.DB实例。

func (me *CommonRepo) Get(query sq.SelectBuilder, dest interface{}) error {
  sqlst, args, err := query.ToSql()
  if err != nil {
    return err
  }
  // 进行一些反射魔法,以便Sqlx不会在interface{}上出错
  v := reflect.ValueOf(dest)
  return me.GetSqlx().Get(v.Interface(), sqlst, args...)
}
func (me *CommonRepo) Select(query sq.SelectBuilder, dest interface{}) error {
  sqlst, args, err := query.ToSql()
  if err != nil {
    return err
  }
  // 进行一些反射魔法,以便Sqlx不会在interface{}上出错
  v := reflect.ValueOf(dest)
  return me.GetSqlx().Select(v.Interface(), sqlst, args...)
}

然后,要调用它,你可以这样做:

func (me *myCustomerRepo) Get(query sq.SelectBuilder) (rec Customer, err error) {
  err = me.CommonRepo.Get(query, &rec)
  return
}
func (me *myCustomerRepo) Select(query sq.SelectBuilder) (recs []Customer, err error) {
  err = me.CommonRepo.Select(query, &recs)
  return
}

这样可以让你在各个地方都有强类型,但是将所有通用逻辑放在一个地方(在这个例子中是CommonRepo)。

英文:

For googlers out there I just ran into the dreaded scannable dest type interface {} with >1 columns (XX) in result error.

Evan Shaw's answer did not work for me. Here is how I solved it. I am also using the lann/squirrel library, but you could easily take that out.

The solution really isn't that complicated, just knowing the magic combination of reflect calls to make.

The me.GetSqlx() function just returns an instance to *sqlx.DB

    func (me *CommonRepo) Get(query sq.SelectBuilder, dest interface{}) error {
      sqlst, args, err := query.ToSql()
      if err != nil {
        return err
      }
      // Do some reflection magic so that Sqlx doesn't hork on interface{}
      v := reflect.ValueOf(dest)
      return me.GetSqlx().Get(v.Interface(), sqlst, args...)
    }
    func (me *CommonRepo) Select(query sq.SelectBuilder, dest interface{}) error {
      sqlst, args, err := query.ToSql()
      if err != nil {
        return err
      }
      // Do some reflection magic so that Sqlx doesn't hork on interface{}
      v := reflect.ValueOf(dest)
      return me.GetSqlx().Select(v.Interface(), sqlst, args...)
    }

Then to invoke it you can do:

    func (me *myCustomerRepo) Get(query sq.SelectBuilder) (rec Customer, err error) {
      err = me.CommonRepo.Get(query, &rec)
      return
    }
    func (me *myCustomerRepo) Select(query sq.SelectBuilder) (recs []Customer, err error) {
      err = me.CommonRepo.Select(query, &recs)
      return
    }

This allows you to have strong types all over but have all the common logic in one place (CommonRepo in this example).

huangapple
  • 本文由 发表于 2011年8月20日 23:49:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/7132848.html
匿名

发表评论

匿名网友

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

确定