在Go泛型中,类型的解引用操作符是`*`。

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

What is the dereference operator of a type in Go generics?

问题

当使用泛型时,可以从任何类型创建指针类型,参见Types Parameter Proposal中的Pointer Method Example部分。示例代码如下:

type Pointer[T any] interface {
	*T // 非接口类型约束元素
    // ... 更多约束 ...
}

那么如何声明一个类型的解引用呢?类似于以下方式:

type Deref[T any] interface {
   ???T  // 如果T=="*int",这将引用"int"
   ...
}

谢谢!

英文:

When doing generics, one can create a pointer type from any type, see Pointer Method Example section in Types Parameter Proposal. Example:

type Pointer[T any] interface {
	*T // non-interface type constraint element
    // ... more constraints ...
}

How does one do the opposite, declare a dereference of a type ? Something like:

type Deref[T any] interface {
   ???T  // If T=="*int", this would refer to "int"
   ...
}

Thanks!

答案1

得分: 2

在类型中,不存在所谓的“类型的解引用”。

指针类型是复合类型,也就是说,你需要一个基本类型作为起点。反过来是不行的。

替代方法

如果你想在约束中强制使用非指针类型,请指定非指针类型:

// 将不允许 *int
type NonPointerInt interface {
    ~int
}

注意事项

  • 上述方法不能适用于任何 T。在类型参数为 T 的类型集中使用 ~T明确禁止的"如果 T 是类型参数或接口类型,则不允许使用 ~T"

  • 你可以将更多相关的类型添加到联合中,例如 ~int | ~int32 | ~int64 等。这样你就可以更接近标准库提供的 constraints.Signed 或类似约束。

  • 你可以添加更多(部分)不相关的类型,例如 ~int | ~string,但这样会减少对具有此约束的值可以执行的操作。

关于你问题中的字母,指针类型 *T 用于从基本类型实现(任意级别的)间接引用,它具有明确的实际含义,与指针作为内存位置的地址的概念相关联。如果没有使用循环定义,一个假设的“解引用类型”在实际意义上是不清楚的。

英文:

There is no such thing as a "dereference of a type".

Pointer types are composite types, i.e. you need a base type to begin with. You can't go the other way around.

What to do instead

If you want to force non-pointer types in a constraint, specify the non-pointer types:

// will disallow *int
type NonPointerInt interface {
    ~int
}

Notes

  • the above is not generalizable to any T. Using ~T in a type set where T is a type parameter is explicitly disallowed: "Using ~T is not permitted if T is a type parameter or if T is an interface type".

  • you may add more related types to the union, e.g. ~int | ~int32 | ~int64
    etc. With this you're getting closer to constraints.Signed or similar constraints offered by the standard lib

  • you may add more (partially) unrelated types, e.g. ~int | ​~string but then you're reducing the operations you can do on values with such constraint.

<hr>

About the letter of your question, a pointer type *T is useful to achieve (arbitrary levels of) indirection from a base type, and it has a precise practical meaning, tied to the concept of a pointer as the address of a memory location. It's unclear what a hypothetical "dereference type" would be in practical terms, without using a circular definition.

答案2

得分: 2

你只能解引用指针值,而不能解引用类型。*T并不是解引用T类型,*T是一个类型字面量,组成一个指针类型,其基本类型将为T

编译器只允许在约束类型上允许的类型参数上进行操作。

使用any,将允许所有类型,甚至是不能解引用其值的非指针类型。

要解引用一个值,它必须是一个指针。一种方法是指定一个参数的类型为*T,就像这个例子中一样:

func deref[T any](p *T) T {
    return *p
}

T可以是任何类型,但*T肯定是一个指针类型,其值可以被解引用。测试一下:

p := &image.Point{1, 2}
x := deref(p)
log.Printf("%T %v\n", x, x)

p := new(int)
*p = 3
x := deref(p)
log.Printf("%T %v\n", x, x)

输出将会是:

2009/11/10 23:00:00 image.Point (1,2)
2009/11/10 23:00:00 int 3

另一种选择是使用只允许指针类型的约束,例如只有*int

func deref2[T interface{ *int }](p T) {
    log.Printf("%T %v\n", *p, *p)
}

测试一下:

p := new(int)
*p = 4
deref2(p)

输出:

2009/11/10 23:00:00 int 4

虽然在这里使用泛型没有用处,你可以直接用*int替换T,而不需要类型参数。

Go Playground上尝试这些例子。

英文:

You can only dereference pointer vaues, but not types. *T is not dereferencing the T type, *T is a type literal, composing a pointer type whose base type will be T.

The compiler only allows operations on values of type parameters that are allowed on the constrained types.

Using any, all types will be allowed, even non-pointer types, whose values cannot be dereferenced.

To dereference a value, it must be a pointer. One way is to specify a parameter to be of type *T like in this example:

func deref[T any](p *T) T {
    return *p
}

T can be of any type, but *T will surely be a pointer type, whose values can be dereferenced. Testing it:

p := &amp;image.Point{1, 2}
x := deref(p)
log.Printf(&quot;%T %v\n&quot;, x, x)

p := new(int)
*p = 3
x := deref(p)
log.Printf(&quot;%T %v\n&quot;, x, x)

Output will be:

2009/11/10 23:00:00 image.Point (1,2)
2009/11/10 23:00:00 int 3

Another option is to use a constraint that allows only pointer types, for example only *int:

func deref2[T interface{ *int }](p T) {
	log.Printf(&quot;%T %v\n&quot;, *p, *p)
}

Testing it:

p := new(int)
*p = 4
deref2(p)

Output:

2009/11/10 23:00:00 int 4

Although using generics here has no use, you could just substitute T with *int, without type parameters.

Try the examples on the Go Playground.

答案3

得分: 0

我刚刚给你一个答案。如果你想使用泛型解引用指针,并且可能存在一种类型不是指针但你仍然想要该类型的零值的情况,那么这个解决方案对你来说是最好的。

使用这个函数,它会检查给定的类型是否为nil,如果是nil,则返回该类型的零值,所以不需要担心底层类型,只要它是一个指针。

如果你将非指针变量传递给函数,将会导致编译错误,所以不需要担心发生恐慌。

你可以在Go Playground上尝试这段代码。

英文:

i have just an answer for you
if you want to dereference pointer with generic and there may be a type which is not a pointer but still you want the zero value of that type then this solution will be best for you

    func Deref[T any](p *T) T {
	  if p != nil {
	  	return *p
	  }
	  var derefed T
	  return derefed
    }

With this function what happens is it checks if the given type is nil or not if it's nil then it will return zero value of the type so no need to worry about underlying type as long as it's a pointer.

if you pass the non pointer variable to function it will be compilation error so no need to worry about panic.

You can try code on Go Playground

huangapple
  • 本文由 发表于 2022年1月24日 15:42:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/70830472.html
匿名

发表评论

匿名网友

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

确定