Reflection Golang:如何使用接口{}类型在片的中间插入值?
我很难理解如何使用Go使用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
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更快。