无法将未指定类型的整数分配给通用结构字段。

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

Unable to assign untyped int to generic struct field

问题

给定一个通用的结构体:

type R2[IDTYPE comparable] struct {
	ID        IDTYPE
	IsActive  bool
}

实现一个接口:

type Storable interface {
	Store(ctx context.Context) error
}

我期望以下定义可以工作:

func (r R2[int]) Store(ctx context.Context) error {
	r.ID = 123 // 不允许
	// ...
	return nil
}

然而,这种方法定义是不允许的。错误信息是:

'123' (类型为未指定的 int) 无法用类型 IDTYPE (int) 表示

在 Go Playground 上的错误信息是:

cannot use 123 (未指定的 int 常量) 作为赋值中的 int 

将其转换为 int(123) 也不起作用。在这种情况下的错误信息是:

cannot use comparable(123) (未指定的 int 常量 123) 作为赋值中的 int 
英文:

Given a generic struct:

type R2[IDTYPE comparable] struct {
	ID        IDTYPE
	IsActive  bool
}

Implementing an interface:

type Storable interface {
	Store(ctx context.Context) error
}

I would expect the following definition to work:

func (r R2[int]) Store(ctx context.Context) error {
	r.ID = 123 // not allowed
	// ...
	return nil
}

However, the method definition is not allowed. The error is:

'123' (type untyped int) cannot be represented by the type IDTYPE (int)

Is it not yet possible to do this kind of generic field assignment in Go?

Addendum:
On go playground the error is:

cannot use 123 (untyped int constant) as int value in assignment

And converting to int(123) does not work. The error in this case is:

cannot use comparable(123) (untyped int constant 123) as int value in assignment

答案1

得分: 1

实例化必须在类型级别上进行,而不是在方法级别上进行,方法不能引入新的类型参数,请参阅https://stackoverflow.com/questions/70668236/how-to-create-generic-method-in-go-method-must-have-no-type-parameters/70668559#70668559

这意味着当您想要使用R2时,您必须为类型参数选择类型参数,并且方法不能更改这些类型,您在R2的实例化中选择的类型将会被"固定"。

还要注意,由于IDTYPE的约束是comparable,例如可能是string,整数123不能在所有情况下分配给ID字段,因为它可能具有string类型。

如果您想要/必须处理多个具体类型的ID,则泛型不是正确的选择。可以使用接口代替:

type R2 struct {
    ID       any
    IsActive bool
}

还要注意,如果您希望修改接收器(例如结构体的字段),则接收器必须是指针。

如果您希望将存储在ID中的值限制为comparable,请使用(泛型)函数。

以下是如何实现的示例:

type R2 struct {
    ID       any
    IsActive bool
}

func (r *R2) Store(ctx context.Context) error {
    setID(r, 123)
    return nil
}

func setID[ID comparable](r *R2, id ID) {
    r.ID = id
}

进行测试:

r := &R2{}
var s Storable = r

s.Store(context.TODO())

fmt.Println(r)

输出结果(在Go Playground上尝试):

&{123 false}

这提供了灵活性(您可以使用setID()设置任何可比较的值到ID字段),并提供了编译时的安全性:尝试设置一个不可比较的值将导致编译时错误,例如:

setID(r, []int{1}) // 错误:[]int不实现comparable
英文:

Instantiation must happen at the type level, not on a method level, and methods can't introduce new type parameters, see https://stackoverflow.com/questions/70668236/how-to-create-generic-method-in-go-method-must-have-no-type-parameters/70668559#70668559

This means when you want to use R2, you then have to choose type arguments for the type parameters, and the methods can't change those, you're "stuck" with the types you choose on R2's instantiation.

Also note that since the constraint for IDTYPE is comparable, which may be string for example, the integer 123 cannot be assigned to the ID field in all cases because it may have a type of string.

If you want / must handle multiple concrete types for the IDs, generics is not the right choice. Interfaces may be used instead:

type R2 struct {
    ID       any
    IsActive bool
}

Also note that the receiver must be a pointer if you wish to modify the receiver (e.g. fields of a struct).

If you wish to restrict the values stored in ID to comparable, use a (generic) function for it.

Here's how you can do it:

type R2 struct {
    ID       any
    IsActive bool
}

func (r *R2) Store(ctx context.Context) error {
    setID(r, 123)
    return nil
}

func setID[ID comparable](r *R2, id ID) {
    r.ID = id
}

Testing it:

r := &R2{}
var s Storable = r

s.Store(context.TODO())

fmt.Println(r)

Which outputs (try it on the Go Playground):

&{123 false}

This provides flexibility (you can set any comparable values to the ID field using setID()), and provides compile-time safety: attempting to set an incomparable value will result in a compile-time error such as this:

setID(r, []int{1}) // Error: []int does not implement comparable

huangapple
  • 本文由 发表于 2022年9月13日 16:02:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/73699475.html
匿名

发表评论

匿名网友

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

确定