英文:
Sum by pointers which are constrained by type parameters
问题
这段代码的问题在于无法将指针类型作为类型参数进行约束。在第二个示例中,指针类型的约束是不允许的,因此代码无法编译通过。在第三个示例中,虽然定义可以编译通过,但是对函数的调用却无法通过编译,因为*int64
并不实现*int32
。第四个示例是可以正常工作的。
关于你的问题:
*Numeric
不被允许,但是T0 Numeric, T1 *T0
是可以的,这是符合预期的。- 除了使用第四个示例中的方法,目前没有更简单的方式了。
英文:
This code works fine:
type Numeric interface {
int32 | int64
}
func SumByPointer[T1 Numeric, T2 Numeric](v1 *T1, v2 *T2) {
*v1 = *v1 + T1(*v2)
}
I want the pointer types to be constrained by type parameters. This is not compiled:
// Err: ./prog.go:11:23: interface contains type constraints
func SumByPointer[T1 *Numeric, T2 *Numeric](v1 T1, v2 T2) {
Here definition is compiled but call to function is not:
func SumByPointer[T0 Numeric, T1 *T0, T2 *T0](v1 T1, v2 T2) {
....
// Err: ./prog.go:19:15: *int64 does not implement *int32
SumByPointer(&v1, &v2)
This works:
func SumByPointer[T0 Numeric, T02 Numeric, T1 *T0, T2 *T02](v1 T1, v2 T2) {
Questions:
-
Is this expected that
*Numeric
is not allowed butT0 Numeric, T1 *T0
works? -
Is there easier way than latter one?
答案1
得分: 2
首先要注意的是,整数之间的转换可能会导致截断。特别是,如果你依赖于调用点处的类型推断,那么你的代码可能会出现微妙的错误,因为根据函数参数的顺序,截断可能会发生。
明确一点:
v1 := int32(10)
v2 := int64(20)
SumByPointer(&v1, &v2)
SumByPointer(&v2, &v1)
这两个调用都是合法的,但第一个调用将int64
转换为int32
,可能会发生截断。有了这个前提:
> 这是预期的,*Numeric 不允许吗?
是的。你的约束Numeric
包括一个类型项,具体来说是并集int32 | int64
,这使得它成为一个非基本接口,而非基本接口只能用作类型约束。
当你写T1 *Numeric
时,Numeric
不再被用作约束。它被用作类型字面量的一部分(一个指针)。如果你考虑到T1 *Numeric
实际上是以下语法糖:
T1 interface{ *Numeric }
当你写T0 Numeric, T1 *T0
时:
Numeric
再次被用作T0
的约束T0
不是一个接口,它是一个类型参数- 你可以将
T0
作为类型字面量*T0
的一部分,然后将其用作T1
的约束——相当于T1 interface { *T0 }
> 有比后者更简单的方法吗?
你的第一个尝试已经很简单了,我建议你坚持使用它:
func SumByPointer[T1 Numeric, T2 Numeric](v1 *T1, v2 *T2) {
*v1 = *v1 + T1(*v2)
}
将指针隐藏在类型参数后面并没有实际带来太多好处。实际上,为了使加法编译通过,你必须将指针排除在并集之外。而为了使转换有效,你必须使用基本类型。所以根据我所见,你的最终尝试也是有些被迫的。
另一种可能的方法是将Numeric
参数化:
type Numeric[T int32 | int64] interface {
*T
}
func SumByPointer[T1 Numeric[N], T2 Numeric[M], N, M int32 | int64](v1 T1, v2 T2) {
*v1 = *v1 + N(*v2)
}
不过,是否认为这种方法更"简单"完全取决于你。从实际角度来看,Numeric
接口仍然是非基本的。
英文:
As a foreword, note that converting between integers may result in truncation. In particular, your code is open to subtle bugs if you rely on type inference at call sites, because then truncation may occur depending on the order of the function arguments.
To be clear:
v1 := int32(10)
v2 := int64(20)
SumByPointer(&v1, &v2)
SumByPointer(&v2, &v1)
Either call compiles, but the first one converts int64
to int32
, which may truncate. With that said:
> Is this expected that *Numeric is not allowed
Yes it is. Your constraint Numeric
includes a type term, specifically the union int32 | int64
, which makes it a non-basic interface, and non-basic interfaces can only be used as type constraints.
When you write T1 *Numeric
, Numeric
is not used as a constraint anymore. It is used as part of a type literal (a pointer). This becomes easier to see if you consider that T1 *Numeric
is actually syntactic sugar for:
T1 interface{ *Numeric }
When you write T0 Numeric, T1 *T0
instead:
Numeric
is again used a constraint ofT0
T0
is not an interface, it is a type parameter- you can use
T0
as part of the type literal*T0
, which then can be used as the constraint forT1
— equivalent toT1 interface { *T0 }
> Is there easier way than latter one?
Your first attempt is quite easy, I would stick to it:
func SumByPointer[T1 Numeric, T2 Numeric](v1 *T1, v2 *T2) {
*v1 = *v1 + T1(*v2)
}
Hiding the pointer behind a type parameter doesn't really accomplish much. In fact, for the addition to compile, you have to keep the pointers out of the union. And for the conversion to be valid you have to use the base types. So your final attempt is also sort of forced, as far as I can see.
An alternative might be to parametrize Numeric
:
type Numeric[T int32 | int64] interface {
*T
}
func SumByPointer[T1 Numeric[N], T2 Numeric[M], N, M int32 | int64](v1 T1, v2 T2) {
*v1 = *v1 + N(*v2)
}
Although whether this appears "easier" is entirely up to you. In practical terms, the Numeric
interface is still non-basic.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论