如何对一个类型为`interface{}`且为切片的变量进行子切片操作?

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

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{}进行子切片呢:

  1. // dst必须是[]S、[]*S、[]I或[]P,其中S是某个结构体类型,I是某个接口类型,
  2. // P是某个非接口非指针类型,使得P或*P实现了PropertyLoadSaver接口。
  3. // 如果是[]I,每个元素必须是Get的有效dst:它必须是结构体指针或实现了PropertyLoadSaver接口。
  4. //
  5. // 作为特例,PropertyList是dst的无效类型,即使PropertyList是结构体的切片。
  6. // 为了避免错误传递,它被视为无效类型,即使本意是传递[]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:

  1. // dst must be a []S, []*S, []I or []P, for some struct type S, some interface
  2. // type I, or some non-interface non-pointer type P such that P or *P
  3. // implements PropertyLoadSaver. If an []I, each element must be a valid dst
  4. // for Get: it must be a struct pointer or implement PropertyLoadSaver.
  5. //
  6. // As a special case, PropertyList is an invalid type for dst, even though a
  7. // PropertyList is a slice of structs. It is treated as invalid to avoid being
  8. // mistakenly passed when []PropertyList was intended.

答案1

得分: 2

由于您是调用datastore.GetMulti的调用者,该函数接受一个interface{}参数,您可以提供任何具体值作为该参数;不需要事先将其转换为空接口类型。换句话说,任何东西都实现了空接口,所以只需传递该对象即可。

  1. func GetMulti() {
  2. mySlice := make([]Whatever, 3000, 3000)
  3. for i := 0; i < 3; i++ {
  4. subSlice := mySlice[i * 1000 : (i + 1) * 1000]
  5. datastore.GetMulti(c,k, subSlice) // 假设已定义 'c' 和 'k'
  6. }
  7. }

如果mypkg.GetMulti应该是一个通用函数,也接受一个interface{}值作为参数,那么您将需要使用反射,就像以下示例中的示例一样,在其中不是使用fmt.Println打印子切片的长度,而是调用datastore.GetMulti来处理每个子切片:

  1. package main
  2. import "fmt"
  3. import "reflect"
  4. func GetMulti(i interface{}) {
  5. v := reflect.ValueOf(i)
  6. if v.Kind() != reflect.Slice {
  7. panic("argument not a slice")
  8. }
  9. l := v.Len()
  10. p := (l / 1000)
  11. for i := 0; i < p; i++ {
  12. fmt.Println(v.Slice(i*1000, (i+1)*1000).Len())
  13. }
  14. fmt.Println(v.Slice(p*1000, l).Len())
  15. }
  16. func main() {
  17. s := make([]int, 3560, 3560)
  18. GetMulti(s)
  19. }
英文:

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.

  1. func GetMulti() {
  2. mySlice := make([]Whatever, 3000, 3000)
  3. for i := 0; i &lt; 3; i++ {
  4. subSlice := mySlice[i * 1000 : (i + 1) * 1000]
  5. datastore.GetMulti(c,k, subSlice) // &#39;c&#39; and &#39;k&#39; assumed to be defined
  6. }
  7. }

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:

  1. package main
  2. import &quot;fmt&quot;
  3. import &quot;reflect&quot;
  4. func GetMulti(i interface{}) {
  5. v := reflect.ValueOf(i)
  6. if v.Kind() != reflect.Slice {
  7. panic(&quot;argument not a slice&quot;)
  8. }
  9. l := v.Len()
  10. p := (l / 1000)
  11. for i := 0; i &lt; p; i++ {
  12. fmt.Println(v.Slice(i*1000, (i+1)*1000).Len())
  13. }
  14. fmt.Println(v.Slice(p*1000, l).Len())
  15. }
  16. func main() {
  17. s := make([]int, 3560, 3560)
  18. GetMulti(s)
  19. }

huangapple
  • 本文由 发表于 2014年4月4日 17:59:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/22859547.html
匿名

发表评论

匿名网友

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

确定