创建未知类型的切片?

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

Create slice of unknown type?

问题

我正在尝试使用这个函数(来自go-couchbase)获取多个值。

func (b *Bucket) Gets(k string, rv interface{}, caso *uint64) error {
    data, _, cas, err := b.GetsRaw(k)
    if err != nil {
        return err
    }
    if caso != nil {
        *caso = cas
    }
    return json.Unmarshal(data, rv)
}

问题是我不知道如何创建 rv 的切片,因为在我的函数中我不知道它的类型,也不知道它的大小,所以无法通过索引访问 rv 切片,对吗?

我想尽可能通用,所以为每个 rv 结构创建一个函数并不是最优解,而且 GetBulk 函数只返回一个 []byte

在 Go 中是否有可能实现我想要的功能呢?

英文:

I'm trying to fetch multiple values using this function (from go-couchbase).

func (b *Bucket) Gets(k string, rv interface{}, caso *uint64) error {
	data, _, cas, err := b.GetsRaw(k)
	if err != nil {
		return err
	}
	if caso != nil {
		*caso = cas
	}
	return json.Unmarshal(data, rv)
}

The problem is that I don't know how to create a slice of rv, since I don't know its type in my function, and I have no idea how big it will be so I can't really access the rv slice through indexes, right?

I want to be as general as possible, so creating a function per rv struct isn't really optimal and the GetBulk function only returns a []byte.

Is it even possible to do what I want in go?

答案1

得分: 7

您可以使用reflect包来检查类型信息。如果我们有一个函数,它有一个参数rv interface{},我们期望传入一个指向切片的指针,我们可以创建一个指向该切片的reflect.Value

slice := reflect.ValueOf(rv).Elem()

我们可以按以下方式重新初始化切片:

slice.Set(reflect.MakeSlice(slice.Type(), length, capacity))

我们可以通过以下方式确定该切片的元素类型:

elemType := slice.Type().Elem()

然后创建另一个表示新分配的该类型实例的指针的reflect.Value

v := reflect.New(elemType)

现在,v.Interface()适合传递给像json.Unmarshal这样的函数。一旦填充完毕,它可以附加到切片中:

slice.Set(reflect.Append(slice, v.Elem()))

有一个完整的示例,将一系列JSON文档解码为任意切片类型,请参见http://play.golang.org/p/G-SHQO2MAT。

英文:

You can inspect the type information using the reflect package. If we have a function that has an argument rv interface{} where we expect a pointer to a slice to be passed in, we can create a reflect.Value that refers to that slice:

slice := reflect.ValueOf(rv).Elem()

We can reinitialise the slice as follows:

slice.Set(reflect.MakeSlice(slice.Type(), length, capacity))

We can determine the element type of this slice with:

elemType := slice.Type().Elem()

And then create another reflect.Value that represents a pointer to a newly allocated instance of that type:

v := reflect.New(elemType)

Now v.Interface() would be appropriate to pass to a function like json.Unmarshal. Once it has been filled, it can be appended to the slice:

slice.Set(reflect.Append(slice, v.Elem()))

For a full example that decodes a slice of JSON documents into an arbitrary slice type, see http://play.golang.org/p/G-SHQO2MAT

答案2

得分: 2

考虑到go-couchbase#Bucket.Gets接受一个接口作为参数,你需要将你的对象放入一个[]interface中,就像wiki页面"InterfaceSlice"中描述的那样。

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
    interfaceSlice[i] = d
}

这意味着你已经有了一个"某种类型"的切片,并且知道它的大小。

或者,如果你想要"围绕Gets函数构建一个函数",你可以使用一个简单的interface{}而不是[]interface,并且具有相同的函数签名。

英文:

Considering go-couchbase#Bucket.Gets takes an interface, you need to put your objects into a []interface, as describe in wiki page "InterfaceSlice"

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
    interfaceSlice[i] = d
}

That means you already have a slice of "something", and know its size.

Or, since you want to "build a function around the Gets function", you could have the same signature, and use a simple interface{} instead of []interface.

huangapple
  • 本文由 发表于 2014年7月16日 17:49:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/24777603.html
匿名

发表评论

匿名网友

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

确定