Is it possible to assert types dynamically in golang?

huangapple go评论118阅读模式
英文:

Is it possible to assert types dynamically in golang?

问题

我有一个名为Deduplicate的方法,它将传入的切片作为interface{}返回去重后的副本。有没有办法将此方法返回的interface{}值转换为与我在此方法中传入的相同类型,而无需显式编写它?例如,如果我将myStruct.RelatedIDs的类型从[]int更改为[]uint,它将阻止代码编译。

以下是代码示例:

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type myStruct struct {
  7. ID int
  8. RelatedIDs []int
  9. }
  10. func main() {
  11. s := &myStruct{
  12. ID: 42,
  13. RelatedIDs: []int{1, 1, 2, 3},
  14. }
  15. v, _ := Deduplicate(s.RelatedIDs)
  16. s.RelatedIDs = v.([]int) // << 在这里我能动态断言类型吗?
  17. // s.RelatedIDs = v.(reflect.TypeOf(s.RelatedIDs)) // 不起作用
  18. fmt.Printf("%#v\n", s.RelatedIDs)
  19. }
  20. func Deduplicate(slice interface{}) (interface{}, error) {
  21. if reflect.TypeOf(slice).Kind() != reflect.Slice {
  22. return nil, fmt.Errorf("slice has wrong type: %T", slice)
  23. }
  24. s := reflect.ValueOf(slice)
  25. res := reflect.MakeSlice(s.Type(), 0, s.Len())
  26. seen := make(map[interface{}]struct{})
  27. for i := 0; i < s.Len(); i++ {
  28. v := s.Index(i)
  29. if _, ok := seen[v.Interface()]; ok {
  30. continue
  31. }
  32. seen[v.Interface()] = struct{}{}
  33. res = reflect.Append(res, v)
  34. }
  35. return res.Interface(), nil
  36. }

请注意,我只会返回翻译好的部分,不会回答关于翻译的问题。

英文:

I have a method Deduplicate that returns deduplicated copy of passed in slice as an interface{}. Is there a way to cast returned by this method interface{} value to the same type as I passed in this method without writing it explicitly? For example, if I change myStruct.RelatedIDs type from []int to []uint it will prevent code from compiling.

https://play.golang.org/p/8OT4xYZuwEn

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;reflect&quot;
  5. )
  6. type myStruct struct {
  7. ID int
  8. RelatedIDs []int
  9. }
  10. func main() {
  11. s := &amp;myStruct{
  12. ID: 42,
  13. RelatedIDs: []int{1, 1, 2, 3},
  14. }
  15. v, _ := Deduplicate(s.RelatedIDs)
  16. s.RelatedIDs = v.([]int) // &lt;&lt; can I assert type dynamically here?
  17. // s.RelatedIDs = v.(reflect.TypeOf(s.RelatedIDs)) // does not work
  18. fmt.Printf(&quot;%#v\n&quot;, s.RelatedIDs)
  19. }
  20. func Deduplicate(slice interface{}) (interface{}, error) {
  21. if reflect.TypeOf(slice).Kind() != reflect.Slice {
  22. return nil, fmt.Errorf(&quot;slice has wrong type: %T&quot;, slice)
  23. }
  24. s := reflect.ValueOf(slice)
  25. res := reflect.MakeSlice(s.Type(), 0, s.Len())
  26. seen := make(map[interface{}]struct{})
  27. for i := 0; i &lt; s.Len(); i++ {
  28. v := s.Index(i)
  29. if _, ok := seen[v.Interface()]; ok {
  30. continue
  31. }
  32. seen[v.Interface()] = struct{}{}
  33. res = reflect.Append(res, v)
  34. }
  35. return res.Interface(), nil
  36. }

答案1

得分: 3

请稍等,我会为您翻译这段代码。

英文:

Try this

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;reflect&quot;
  5. )
  6. type myStruct struct {
  7. ID int
  8. RelatedIDs []int
  9. }
  10. func main() {
  11. s := &amp;myStruct{
  12. ID: 42,
  13. RelatedIDs: []int{1, 1, 2, 3},
  14. }
  15. err := Deduplicate(&amp;s.RelatedIDs)
  16. fmt.Println(err)
  17. // s.RelatedIDs = v.([]int) // &lt;&lt; can I assert type dynamically here?
  18. // s.RelatedIDs = v.(reflect.TypeOf(s.RelatedIDs)) // does not work
  19. fmt.Printf(&quot;%#v\n&quot;, s.RelatedIDs)
  20. }
  21. func Deduplicate(slice interface{}) error {
  22. rts := reflect.TypeOf(slice)
  23. rtse := rts.Elem()
  24. if rts.Kind() != reflect.Ptr &amp;&amp; rtse.Kind() != reflect.Slice {
  25. return fmt.Errorf(&quot;slice has wrong type: %T&quot;, slice)
  26. }
  27. rvs := reflect.ValueOf(slice)
  28. rvse := rvs.Elem()
  29. seen := make(map[interface{}]struct{})
  30. var e int
  31. for i := 0; i &lt; rvse.Len(); i++ {
  32. v := rvse.Index(i)
  33. if _, ok := seen[v.Interface()]; ok {
  34. continue
  35. }
  36. seen[v.Interface()] = struct{}{}
  37. rvse.Index(e).Set(v)
  38. e++
  39. }
  40. rvse.SetLen(e)
  41. rvs.Elem().Set(rvse)
  42. return nil
  43. }

https://play.golang.org/p/hkEW4u1aGUi

with future generics, it might look like this https://go2goplay.golang.org/p/jobI5wKR8fU

答案2

得分: 2

以下是翻译好的内容:

为了完整起见,这里是一个通用版本的代码(Playground),它不需要使用反射。只能在2022年2月之后打开!然而,关于NaN常规注意事项仍然适用。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. s := []int{1, 1, 2, 3}
  7. res := Deduplicate(s)
  8. fmt.Printf("%#v\n", res)
  9. }
  10. func Deduplicate[T comparable](s []T) []T {
  11. seen := make(map[T]struct{})
  12. res := make([]T, 0, len(s))
  13. for _, elem := range s {
  14. if _, exists := seen[elem]; exists {
  15. continue
  16. }
  17. seen[elem] = struct{}{}
  18. res = append(res, elem)
  19. }
  20. return res
  21. }

输出结果:

  1. []int{1, 2, 3}
英文:

For completeness, here is a generic version (Playground), which doesn't require reflection. Only open in February 2022! The usual caveats about NaN apply, though.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. )
  5. func main() {
  6. s := []int{1, 1, 2, 3}
  7. res := Deduplicate(s)
  8. fmt.Printf(&quot;%#v\n&quot;, res)
  9. }
  10. func Deduplicate[T comparable](s []T) []T {
  11. seen := make(map[T]struct{})
  12. res := make([]T, 0, len(s))
  13. for _, elem := range s {
  14. if _, exists := seen[elem]; exists {
  15. continue
  16. }
  17. seen[elem] = struct{}{}
  18. res = append(res, elem)
  19. }
  20. return res
  21. }

Output:

  1. []int{1, 2, 3}

huangapple
  • 本文由 发表于 2021年7月24日 03:00:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/68503982.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定