Reflection Golang:如何使用接口{}类型在片的中间插入值?

Reflection Golang:如何使用接口{}类型在片的中间插入值?,reflection,go,Reflection,Go,我很难理解如何使用Go使用interface{}类型 在这个例子中,我有一个函数,它将一个值插入到片的中间某处。看起来是这样的: type mystruct { a, b, c int } func insert(ar []mystruct, val mystruct, i int) []mystruct { l := len(ar) if l == cap(ar) { tmp := make([]mystruct, l + 1, (l * 2) + 1

我很难理解如何使用Go使用
interface{}
类型

在这个例子中,我有一个函数,它将一个值插入到片的中间某处。看起来是这样的:

type mystruct {
    a, b, c int
}

func insert(ar []mystruct, val mystruct, i int) []mystruct {
    l := len(ar)
    if l == cap(ar) {
        tmp := make([]mystruct, l + 1, (l * 2) + 1)
        copy(tmp, ar[0:i])
        copy(tmp[i+1:], ar[i:])
        ar = tmp
    } else {
        ar = ar[0:l+1]
        copy(ar[i+1:], ar[i:])
    }
    ar[i] = val

    return ar
}
return result.Interface()
我希望该函数能够同时接受
ar
val
interface{}
,这样我就可以向它传递任何类型的片和值,并且它可以毫无怨言地执行插入

从目前为止我所读到的内容来看,我认为这应该通过
reflect
包来实现。我已经阅读了反射规则和关于反射和
接口{}
的各种教程,但我不确定如何处理这个问题。我希望尽可能地减少开销,我知道反射会让代码慢一点,但最有效的方法是什么

谢谢

整个“能力增长”代码是不必要的;使用内置的
附加功能
–它正好为您完成这一功能

将签名更改为:

func insert(ar interface{}, val interface{}, i int) interface{}
然后检查
ar
是否为切片,以及
ar
的元素类型是否与
val
的类型相同:

at, vt := reflect.TypeOf(ar), reflect.Typeof(val)

if at.Kind() != reflect.Slice {
    panic(fmt.Sprintf("expected slice, got %T", at))
}

if at.Elem() != vt {
    panic("first argument must be a slice of the second argument's type")
}
类型验证后,获取一些
reflect.Value
s:

av, vv := reflect.ValueOf(ar), reflect.ValueOf(val)
并使用以下工具移动物品,例如:

  • (reflect.Value).索引(int)
    以访问切片的元素
  • reflect.Copy
    复制内置的
    Copy
  • reflect.Append
    附加到切片
  • (reflect.Value).Set(reflect.Value)
    设置可设置元素的值(例如,从切片中获取的内容)
  • reflect.Append
    reflect.AppendSlice
    将内置的
    Append
    附加到切片
一旦您有了表示结果切片的最终
reflect.Value
;将其作为
接口{}
返回,如下所示:

type mystruct {
    a, b, c int
}

func insert(ar []mystruct, val mystruct, i int) []mystruct {
    l := len(ar)
    if l == cap(ar) {
        tmp := make([]mystruct, l + 1, (l * 2) + 1)
        copy(tmp, ar[0:i])
        copy(tmp[i+1:], ar[i:])
        ar = tmp
    } else {
        ar = ar[0:l+1]
        copy(ar[i+1:], ar[i:])
    }
    ar[i] = val

    return ar
}
return result.Interface()

不要试图在Go中编写这种函数。它们编写起来很复杂,执行速度很慢,通常没有你想象的那么有用。@fuzzxl,你是什么意思,不要这样做?我必须执行这个操作——这是一个真实世界的应用程序,用Go编写,它需要完全做到这一点。我可以不必像上面每次那样使用
接口{}
就可以做到这一点,但这意味着要复制、粘贴和修改代码数百次。您有什么建议?@Alasdair您可以创建一个只存储
接口{}
的通用函数,当您从该列表中读取时,将其转换为您存储到其中的任何内容。例如,Go的标准库的链表包就是这样工作的。@Alasdair切片中的类型每次都不同吗?在片的中间插入一个值是一个O(n)操作;当这是一个非常常见的操作时,您可能需要考虑不同的数据结构。我之所以不使用AppEnter是因为我假设它会减慢增长,因为我需要将它复制到两个部分:插入索引之前的所有内容和之后的所有内容。Append会复制所有内容,然后我会再次复制。我试图避免复制整个片段的两个副本。虽然我不确定这是否更有效,因为如果不是从Go源代码编译append,它可能会更快,但理论上我所做的比使用append更快。