如何使用反射创建结构体的切片?

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

How to create slice of struct using reflection?

问题

我需要使用反射从接口创建一个结构体切片。

我使用反射是因为在不使用它的情况下,我没有看到其他解决方案。

简要来说,该函数接收接口的可变值。

然后,使用反射创建切片并将其传递给另一个函数。

反射要求类型断言

SliceVal.Interface().(SomeStructType)

但是我不能使用它。

在playground上的代码:http://play.golang.org/p/EcQUfIlkTe

代码:

package main

import (
    "fmt"
    "reflect"
)

type Model interface {
    Hi()
}

type Order struct {
    H string
}

func (o Order) Hi() {
    fmt.Println("hello")
}

func Full(m []Order) []Order {
    o := append(m, Order{H: "Bonjour"})
    return o
}

func MakeSlices(models ...Model) {
    for _, m := range models {
        v := reflect.ValueOf(m)
        fmt.Println(v.Type())
        sliceType := reflect.SliceOf(v.Type())
        emptySlice := reflect.MakeSlice(sliceType, 1, 1)
        Full(emptySlice.Interface())
    }
}

func main() {
    MakeSlices(Order{})
}
英文:

I need to create a slice of struct from its interface with reflection.

I used Reflection because do not see any other solution without using it.

Briefly, the function receives variadic values of Interface.

Then, with reflection creates slice and passes it into another function.

Reflection asks to type assertion

SliceVal.Interface().(SomeStructType)

But, I cannot use it.

Code in playground http://play.golang.org/p/EcQUfIlkTe

The code:

package main

import (
    "fmt"
    "reflect"
)

type Model interface {
    Hi()
}

type Order struct {
    H string
}

func (o Order) Hi() {
    fmt.Println("hello")
}

func Full(m []Order) []Order{
    o := append(m, Order{H:"Bonjour"}
    return o
}

func MakeSlices(models ...Model) {
    for _, m := range models {
	    v := reflect.ValueOf(m)
	    fmt.Println(v.Type())
	    sliceType := reflect.SliceOf(v.Type())
	    emptySlice := reflect.MakeSlice(sliceType, 1, 1)
	    Full(emptySlice.Interface())
    }
}
func main() {
    MakeSlices(Order{})
}

答案1

得分: 4

你快要成功了。问题在于你不需要将类型断言为结构体类型,而是需要断言为切片类型。

所以,不要使用以下代码:

SliceVal.Interface().(SomeStructType)

而应该使用:

SliceVal.Interface().([]SomeStructType)

在你的具体示例中,只需更改以下一行即可使代码正常工作:

Full(emptySlice.Interface().([]Order))

现在,如果你有多个可能的模型,你可以这样做:

switch s := emptySlice.Interface().(type) {
case []Order:
    Full(s)
case []SomeOtherModel:
    FullForOtherModel(s)
// 等等
}
英文:

You're almost there. The problem is that you don't need to type-assert to the struct type, but to the slice type.

So instead of

SliceVal.Interface().(SomeStructType)

You should do:

SliceVal.Interface().([]SomeStructType)

And in your concrete example - just changing the following line makes your code work:

Full(emptySlice.Interface().([]Order))

Now, if you have many possible models you can do the following:

switch s := emptySlice.Interface().(type) {
case []Order:
    Full(s)
case []SomeOtherModel:
    FullForOtherModel(s)
// etc
}

huangapple
  • 本文由 发表于 2015年3月10日 18:15:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/28961004.html
匿名

发表评论

匿名网友

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

确定