英文:
Golang: how to use interface{} type to insert a value into the middle of a slice?
问题
我在使用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
}
我希望这个函数能够接受interface{}
类型的参数,以便我可以传递任意类型的切片和值,并且它能够正常执行插入操作。
根据我目前的阅读,我相信应该使用reflect
包来实现这个目标。我已经阅读了有关反射和interface{}
的规则以及各种反射和interface{}
的教程,但我不确定如何着手解决这个问题。我希望尽量减少开销,我知道反射会使代码变慢一些,但最高效的方法是什么呢?
谢谢!
英文:
I'm having difficulty getting my head around the usage of interface{}
types with Go.
In this instance I have a function which inserts a value into the middle of a slice somewhere. It looks like this:
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
}
I'd like for that function to be able to accept interface{}
for both ar
and val
so that I could pass it a slice and value of any type and it would perform the insert without complaint.
From what I have read so far I believe this should be done with the reflect
package. I have read the Rules of Reflection and various tutorials on reflection and interface{}
, but I'm not sure how to approach this. I'd like to minimize overhead as much as possible, I understand reflection is going to slow the code down a bit but what is the most efficient way of doing this?
Thanks!
答案1
得分: 1
整个“grow if at capacity”代码是不必要的;使用内置的append
函数即可完成相同的功能。
将函数签名改为:
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
:
av, vv := reflect.ValueOf(ar), reflect.ValueOf(val)
然后可以使用以下方法来移动数据:
(reflect.Value).Index(int)
:访问切片的元素。reflect.Copy
:类似于内置的copy
函数,用于在切片之间进行复制。reflect.Append
:用于向切片Value
追加元素。(reflect.Value).Set(reflect.Value)
:用于设置可设置的元素的值(例如从切片中获取的元素)。reflect.Append
或reflect.AppendSlice
:类似于内置的append
函数,用于向切片追加元素。
一旦得到表示结果切片的最终reflect.Value
,将其作为interface{}
返回,如下所示:
return result.Interface()
英文:
The whole "grow if at capactiy" code is unnecessary; use the built-in append
– it does exactly that for you.
Change the signature to:
func insert(ar interface{}, val interface{}, i int) interface{}
Then check that ar
is a slice and that the element type of ar
is the same type as 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")
}
After type validation, get a hold of some reflect.Value
s:
av, vv := reflect.ValueOf(ar), reflect.ValueOf(val)
And get moving stuff around using e.g:
(reflect.Value).Index(int)
to access element of the slice.reflect.Copy
to copy to and from slices à la built-incopy
reflect.Append
to append to a sliceValue
(reflect.Value).Set(reflect.Value)
to set the value of a settable element (something you got out of a slice, for instance).reflect.Append
orreflect.AppendSlice
to append to a slice à la built-inappend
.
Once you have your final reflect.Value
representing the result slice; return it as an interface{}
like this:
return result.Interface()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论