如何解决是否可以在 golang 中动态断言类型?
我有一个方法 Deduplicate,它返回作为接口传入的切片的重复数据删除副本{}。有没有办法将这个方法 interface{} 返回的值转换为与我在这个方法中传递的值相同的类型而无需显式编写它?例如,如果我将 myStruct.RelatedIDs 类型从 []int 更改为 []uint,它将阻止代码编译。
https://play.golang.org/p/8OT4xYZuwEn
package main
import (
"fmt"
"reflect"
)
type myStruct struct {
ID int
RelatedIDs []int
}
func main() {
s := &myStruct{
ID: 42,RelatedIDs: []int{1,1,2,3},}
v,_ := Deduplicate(s.RelatedIDs)
s.RelatedIDs = v.([]int) // << can I assert type dynamically here?
// s.RelatedIDs = v.(reflect.TypeOf(s.RelatedIDs)) // does not work
fmt.Printf("%#v\n",s.RelatedIDs)
}
func Deduplicate(slice interface{}) (interface{},error) {
if reflect.TypeOf(slice).Kind() != reflect.Slice {
return nil,fmt.Errorf("slice has wrong type: %T",slice)
}
s := reflect.ValueOf(slice)
res := reflect.MakeSlice(s.Type(),s.Len())
seen := make(map[interface{}]struct{})
for i := 0; i < s.Len(); i++ {
v := s.Index(i)
if _,ok := seen[v.Interface()]; ok {
continue
}
seen[v.Interface()] = struct{}{}
res = reflect.Append(res,v)
}
return res.Interface(),nil
}
解决方法
试试这个
package main
import (
"fmt"
"reflect"
)
type myStruct struct {
ID int
RelatedIDs []int
}
func main() {
s := &myStruct{
ID: 42,RelatedIDs: []int{1,1,2,3},}
err := Deduplicate(&s.RelatedIDs)
fmt.Println(err)
// s.RelatedIDs = v.([]int) // << can I assert type dynamically here?
// s.RelatedIDs = v.(reflect.TypeOf(s.RelatedIDs)) // does not work
fmt.Printf("%#v\n",s.RelatedIDs)
}
func Deduplicate(slice interface{}) error {
rts := reflect.TypeOf(slice)
rtse := rts.Elem()
if rts.Kind() != reflect.Ptr && rtse.Kind() != reflect.Slice {
return fmt.Errorf("slice has wrong type: %T",slice)
}
rvs := reflect.ValueOf(slice)
rvse := rvs.Elem()
seen := make(map[interface{}]struct{})
var e int
for i := 0; i < rvse.Len(); i++ {
v := rvse.Index(i)
if _,ok := seen[v.Interface()]; ok {
continue
}
seen[v.Interface()] = struct{}{}
rvse.Index(e).Set(v)
e++
}
rvse.SetLen(e)
rvs.Elem().Set(rvse)
return nil
}
https://play.golang.org/p/hkEW4u1aGUi
对于未来的泛型,它可能看起来像这样 https://go2goplay.golang.org/p/jobI5wKR8fU
,为了完整起见,这里是一个通用版本 (Playground),它不需要反射。仅在 February 2022 开放!不过usual caveats about NaN
适用。
package main
import (
"fmt"
)
func main() {
s := []int{1,3}
res := Deduplicate(s)
fmt.Printf("%#v\n",res)
}
func Deduplicate[T comparable](s []T) []T {
seen := make(map[T]struct{})
res := make([]T,len(s))
for _,elem := range s {
if _,exists := seen[elem]; exists {
continue
}
seen[elem] = struct{}{}
res = append(res,elem)
}
return res
}
输出:
[]int{1,3}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。