英文:
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论