admin管理员组文章数量:1123672
Let's say we have two named types that derive from int:
type Number1 int
type Number2 int
Since their underlying type is the same, they are assignable to each other, so this works
var x Number1 = 42
var y Number2 = Number2(x)
However, if we have slices, they're not directly assignable:
sl1 := []Number1{1, 2, 3}
sl2 := []Number2(sl1) // doesn't work
But we can just make a copy of the slice:
sl2 := make([]Number2, len(sl1))
for i, v := range sl1 {
sl2[i] = Number2(v)
}
We can even define a generic function over ints to do the conversion:
func Convert[To ~int, From ~int](from []From) []To {
to := make([]To, len(from))
for i, v := range from {
to[i] = To(v)
}
return to
}
and use it like that: var sl2 []Number2 = Convert[Number2](sl1)
. This works fine.
My question is: is there a way to make Convert work with any 2 generic types From/To (not just types whose underlying type is int) as long as From is assignable to To?
I've tried a few things but I've not been able to make it work. Basically what I want is something like
func Convert[To ~E, From ~E, E any](from []From) []To { // invalid!
...
}
except this is not allowed because E cannot be a type parameter in ~E.
So, is there a solution? If yes, please provide an example, if no, please explain why it's not possible.
Let's say we have two named types that derive from int:
type Number1 int
type Number2 int
Since their underlying type is the same, they are assignable to each other, so this works
var x Number1 = 42
var y Number2 = Number2(x)
However, if we have slices, they're not directly assignable:
sl1 := []Number1{1, 2, 3}
sl2 := []Number2(sl1) // doesn't work
But we can just make a copy of the slice:
sl2 := make([]Number2, len(sl1))
for i, v := range sl1 {
sl2[i] = Number2(v)
}
We can even define a generic function over ints to do the conversion:
func Convert[To ~int, From ~int](from []From) []To {
to := make([]To, len(from))
for i, v := range from {
to[i] = To(v)
}
return to
}
and use it like that: var sl2 []Number2 = Convert[Number2](sl1)
. This works fine.
My question is: is there a way to make Convert work with any 2 generic types From/To (not just types whose underlying type is int) as long as From is assignable to To?
I've tried a few things but I've not been able to make it work. Basically what I want is something like
func Convert[To ~E, From ~E, E any](from []From) []To { // invalid!
...
}
except this is not allowed because E cannot be a type parameter in ~E.
So, is there a solution? If yes, please provide an example, if no, please explain why it's not possible.
Share Improve this question asked 21 hours ago GohuGohu 2,1072 gold badges18 silver badges19 bronze badges 3 |1 Answer
Reset to default -4You could do this using reflection (Go Playground):
func Convert[To, From any](from []From) []To {
f := reflect.TypeFor[From]()
t := reflect.TypeFor[To]()
if !f.ConvertibleTo(t) {
return nil
}
to := reflect.MakeSlice(reflect.SliceOf(t), len(from), len(from))
for i, v := range from {
to.Index(i).Set(reflect.ValueOf(v).Convert(t))
}
return to.Interface().([]To)
}
The disadvantage is that it wouldn't be type safe and checked only during run time.
You can't force this in a generic function API, since the Go specification states:
In a term of the form ~T, the underlying type of T must be itself, and T cannot be an interface.
and
The type T in a term of the form T or ~T cannot be a type parameter, ...
So, [To ~E, From ~E, E any]
, is an invalid expression, since E
is a type parameter.
The rationale it that the compiler can provide specialized code for concrete types, while it would have to use reflection in the general case, so you would end up with the above solution.
A way to have a little more type safety (but not a function signature) would be:
sl2 := unsafe.Slice((*Number2)(unsafe.SliceData(sl1)), len(sl1))
using unsafe.Slice
, referencing the original array. This is type checked, since:
A non-constant value x can be converted to type T in any of these cases:
... x's type and T are pointer types that [...], and their pointer base types [...] have identical underlying types.
本文标签: goIs a generic slice conversion function possibleStack Overflow
版权声明:本文标题:go - Is a generic slice conversion function possible? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736579554a1944931.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Convert[To ~E, From ~E, E any](from From) To { return To(from) }
-- is also impossible. – Paul Hankin Commented 20 hours ago