反射一个空切片的底层类型的字段?

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

Reflecting The Fields of a Empty's Slices Underyling Type?

问题

我有以下的查询构建函数:

func CreateQuery(t interface{}, where string) {
    var b bytes.Buffer
    b.WriteString("SELECT ")
    
    s := reflect.ValueOf(t).Elem()
    typeOfT := s.Type()
    
    for i := 0; i < s.NumField() - 1; i++ {
        b.WriteString(fmt.Sprintf("%s, ", typeOfT.Field(i).Name))
    }
    
    // 最后一个字段没有逗号
    b.WriteString(fmt.Sprintf("%s ", typeOfT.Field(s.NumField() - 1).Name))
    
    b.WriteString(fmt.Sprintf("FROM %s ", typeOfT.Name()))
    b.WriteString(where)
    fmt.Println(b.String())
}

当以以下方式调用时,它可以正常工作:

var dst FooStruct
CreateQuery(&dst, "")

但是以下代码会引发一个"call of reflect.Value.NumField on slice Value"的错误:

var dst []FooStruct
CreateQuery(&dst, "")

我该如何修改函数以打印切片的底层结构类型的字段?看起来我需要反转reflect的SliceOf函数。

英文:

I have the following query builder function:

func CreateQuery(t interface{}, where string) {
	var b bytes.Buffer
	b.WriteString(&quot;SELECT &quot;)
	
	s := reflect.ValueOf(t).Elem()
	typeOfT := s.Type()
	
	for i := 0; i &lt; s.NumField() - 1; i++ {
		b.WriteString(fmt.Sprintf(&quot;%s, &quot;, typeOfT.Field(i).Name))
	}
	
	//Last one has no Comma
	b.WriteString(fmt.Sprintf(&quot;%s &quot;, typeOfT.Field(s.NumField() - 1).Name))
	
	b.WriteString(fmt.Sprintf(&quot;FROM %s &quot;, typeOfT.Name()))
	b.WriteString(where)
	fmt.Println(b.String())
}

There works fine when called as follows:

var dst FooStruct
CreateQuery(&amp;dst, &quot;&quot;)

But the following raises a "call of reflect.Value.NumField on slice Value" Panic:

var dst []FooStruct
CreateQuery(&amp;dst, &quot;&quot;)

How I can I make the function print the fields of a slice's underlying struct type? It seems like I want the inverse of reflect's SliceOf function.

答案1

得分: 3

你只能在表示结构体的reflect.Type上调用NumFieldField方法(即t.Kind() == reflect.Struct)。

如果你有一个切片类型,你可以通过Elem方法访问其中包含的类型,该方法返回另一个reflect.Type。如果切片包含一个结构体,那么你可以在该类型上调用NumField/Field方法。

英文:

You can only call NumField or Field methods on a reflect.Type representing a struct (i.e. t.Kind() == reflect.Struct).

If you have a slice type, you can access the contained type via the Elem method, which returns another reflect.Type. If the slice contains a struct, then you can call NumField/Field on this type.

答案2

得分: 1

你可以遍历切片,在每个查询上调用CreateQuery函数:

func CreateQueries(t interface{}, where string) {
    v := reflect.ValueOf(t)

    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }

    if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
        for i := 0; i < v.Len(); i++ {
            CreateQuery(v.Index(i).Interface(), where)
        }
    }
}

使用reflect.Value.Index可以单独访问每个字段,调用.Interface()方法可以将值转换为interface{}类型的表示,使其适用于放入CreateQuery函数中(该函数期望一个interface{}值)。

英文:

You can iterate over the slice, calling CreateQuery for every query:

func CreateQueries(t interface{}, where string) {
	v := reflect.ValueOf(t)

	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
		for i := 0; i &lt; v.Len(); i++ {
			CreateQuery(v.Index(i).Interface(), where)
		}
	}
}

Using reflect.Value.Index you can access each field separately, calling .Interface() on the
value yields the interface{} type representation of that value, making it suitable to put
it in your CreateQuery function (which expects a interface{} value).

huangapple
  • 本文由 发表于 2013年12月10日 22:04:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/20496585.html
匿名

发表评论

匿名网友

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

确定