如何确定切片界面的元素类型{}?

时间:2017-02-10 04:02:57

标签: go

我有以下代码来加倍切片。

func doubleSlice(s []int) []int  {
  t := make([]int, len(s), (cap(s) + 1) * 2 )
  for i := range s {
    t[i] = s[i]
  }
  return t
}

我想让func加倍任何类型的切片。我需要先了解元素类型。

func showInterfaceItem(s interface{}) interface{} {
  if reflect.TypeOf(s).Kind() != reflect.Slice {
    fmt.Println("The interface is not a slice.")
    return
  }

  var t interface{}
  newLen := reflect.ValueOf(s).Len()
  newCap := (cap(reflect.ValueOf(s).Cap()) + 1) * 2
  t = make([]reflect.TypeOf(s), newLen, newCap)

  return t
}

reflect.TypeOf(s)返回接口{}的类型,而不是元素的类型。如何获得切片接口的元素类型?

2 个答案:

答案 0 :(得分:4)

您可以使用package main import ( "fmt" "reflect" ) func doubleSlice(s interface{}) interface{} { if reflect.TypeOf(s).Kind() != reflect.Slice { fmt.Println("The interface is not a slice.") return nil } v := reflect.ValueOf(s) newLen := v.Len() newCap := (v.Cap() + 1) * 2 typ := reflect.TypeOf(s).Elem() t := reflect.MakeSlice(reflect.SliceOf(typ), newLen, newCap) reflect.Copy(t, v) return t.Interface() } func main() { xs := doubleSlice([]string{"foo", "bar"}).([]string) fmt.Println("data =", xs, "len =", len(xs), "cap =", cap(xs)) ys := doubleSlice([]int{3, 1, 4}).([]int) fmt.Println("data =", ys, "len =", len(ys), "cap =", cap(ys)) } 获得切片元素的类型。

data = [foo bar] len = 2 cap = 6
data = [3 1 4] len = 3 cap = 8

输出将是:

{{1}}

检查:Go Playground

答案 1 :(得分:0)

这在 golang 中是可行的,我花了一整天的时间来发现模式。

首先,我们想得到一个 slice 的指针来让 gorm 开心,它的类型是 "*[]Obj"。为了在 golang 中实现这一点,我们可以像这样创建一个 make 包装器:

func makeWrapper(cap uint) interface{} {
    arr:= make([]Sth, 0, cap)
    return &arr
}

注意,我们不能直接引用maked的值,这可能是簿记数据需要有一个堆栈空间来存储。

//Not working example
func makeWrapper(cap uint) interface{} {
    return &(make([]Sth, 0, cap))
}

和之前的答案一样,reflect.MakeSlice(reflect.SliceOf(typ), 0, capacity).Interface() 返回 interface{[]Sth}。 (这里的typ是指reflect.TypeOf(Sth{}),相当于typ == reflect.TypeOf(v)

因此我们需要创建一个*[]Sth的返回对象,里面的值是一个有容量的切片[]Sth。理解目标后,我们可以有这样的代码:

package main

import (
    "reflect"
)

type Sth struct {
    a, b string
}
func main() {
    af:= createSlice(Sth{})
    arr := makeWrapper(10).(*[]Sth)
    println(reflect.TypeOf(arr).String())

    // equiv to makeWrapper, but we do it via reflection
    arr = af(10).(*[]Sth)
    println(reflect.TypeOf(arr).String())
}

func makeWrapper(cap uint) interface{} {
    arr:= make([]Sth, 0, cap)
    return &arr
}

func createSlice(v interface{}) func(int) interface{} {
    var typ reflect.Type
    if reflect.ValueOf(v).Kind() == reflect.Ptr {
        typ = reflect.ValueOf(v).Elem().Type()
    } else if  reflect.ValueOf(v).Kind() == reflect.Struct {
        typ = reflect.TypeOf(v)
    } else {
        panic("only support instance of struct or pointer of that instance")
    }

    return func(capacity int) interface{}{
        // create the outer object saves our slice
        outerObj:=reflect.New(reflect.SliceOf(typ))
        // create the slice and save it to return
        outerObj.Elem().Set(reflect.MakeSlice(reflect.SliceOf(typ), 0, capacity))
        // retrive the interface of outer object
        return outerObj.Interface()
    }
}