英文:
How to sub slice an interface{} that is a slice?
问题
datastore.GetMulti(c appengine.Context, key []*Key, dst interface{})
API允许我最多获取1000个实体。我想获取更多。
解决这个问题的一种明显的方法是创建一个包装函数mypkg.GetMulti()
,它对原始参数进行子切片(key[0:1000], key[1000:2000]...
),然后多次使用这些子切片调用datastore.GetMulti()
。
很明显如何对key []*Key
进行子切片,但如何对可能是以下类型的dst interface{}
进行子切片呢:
// dst必须是[]S、[]*S、[]I或[]P,其中S是某个结构体类型,I是某个接口类型,
// P是某个非接口非指针类型,使得P或*P实现了PropertyLoadSaver接口。
// 如果是[]I,每个元素必须是Get的有效dst:它必须是结构体指针或实现了PropertyLoadSaver接口。
//
// 作为特例,PropertyList是dst的无效类型,即使PropertyList是结构体的切片。
// 为了避免错误传递,它被视为无效类型,即使本意是传递[]PropertyList。
英文:
The datastore.GetMulti(c appengine.Context, key []*Key, dst interface{})
API allows me to get 1000 entities at most. I want to get more.
An obvious way to solve this generically is to create a wrapper function mypkg.GetMulti()
which sub slices (key[0:1000], key[1000:2000]...
) the original arguments and calls datastore.GetMulti()
several times with them.
It's pretty clear how to sub slice key []*Key
, but how do I sub slice dst interface{}
which could be:
// dst must be a []S, []*S, []I or []P, for some struct type S, some interface
// type I, or some non-interface non-pointer type P such that P or *P
// implements PropertyLoadSaver. If an []I, each element must be a valid dst
// for Get: it must be a struct pointer or implement PropertyLoadSaver.
//
// As a special case, PropertyList is an invalid type for dst, even though a
// PropertyList is a slice of structs. It is treated as invalid to avoid being
// mistakenly passed when []PropertyList was intended.
答案1
得分: 2
由于您是调用datastore.GetMulti
的调用者,该函数接受一个interface{}
参数,您可以提供任何具体值作为该参数;不需要事先将其转换为空接口类型。换句话说,任何东西都实现了空接口,所以只需传递该对象即可。
func GetMulti() {
mySlice := make([]Whatever, 3000, 3000)
for i := 0; i < 3; i++ {
subSlice := mySlice[i * 1000 : (i + 1) * 1000]
datastore.GetMulti(c,k, subSlice) // 假设已定义 'c' 和 'k'
}
}
如果mypkg.GetMulti
应该是一个通用函数,也接受一个interface{}
值作为参数,那么您将需要使用反射,就像以下示例中的示例一样,在其中不是使用fmt.Println
打印子切片的长度,而是调用datastore.GetMulti
来处理每个子切片:
package main
import "fmt"
import "reflect"
func GetMulti(i interface{}) {
v := reflect.ValueOf(i)
if v.Kind() != reflect.Slice {
panic("argument not a slice")
}
l := v.Len()
p := (l / 1000)
for i := 0; i < p; i++ {
fmt.Println(v.Slice(i*1000, (i+1)*1000).Len())
}
fmt.Println(v.Slice(p*1000, l).Len())
}
func main() {
s := make([]int, 3560, 3560)
GetMulti(s)
}
英文:
Since you are the caller of datastore.GetMulti
which takes an interface{}
argument, you can provide any concrete value as that argument; it doesn't need to be converted to the empty-interface type beforehand. In other words, anything and everything implements the empty interface, so just pass that thing.
func GetMulti() {
mySlice := make([]Whatever, 3000, 3000)
for i := 0; i < 3; i++ {
subSlice := mySlice[i * 1000 : (i + 1) * 1000]
datastore.GetMulti(c,k, subSlice) // 'c' and 'k' assumed to be defined
}
}
In case mypkg.GetMulti
should be a generic function, taking an interface{}
value as well, then you'll have to use reflection as in the following example where instead of fmt.Println
with the length of the subslice you'd call datastore.GetMulti
with each subslice:
package main
import "fmt"
import "reflect"
func GetMulti(i interface{}) {
v := reflect.ValueOf(i)
if v.Kind() != reflect.Slice {
panic("argument not a slice")
}
l := v.Len()
p := (l / 1000)
for i := 0; i < p; i++ {
fmt.Println(v.Slice(i*1000, (i+1)*1000).Len())
}
fmt.Println(v.Slice(p*1000, l).Len())
}
func main() {
s := make([]int, 3560, 3560)
GetMulti(s)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论