泛型:约束和嵌入在接口中的结构体

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

Generics: constraints and struct embedded in interface

问题

以下是代码的中文翻译:

package main

import "fmt"

type Test struct {
    Name string
}

func (t Test) String() string {
    return fmt.Sprintf("Name: %v", t.Name)
}

type StructWithName struct {
    Name string
}

type Constraint interface {
    StructWithName
    // ~struct {
    // 	Name string
    // }
    String() string
}

func Print[T Constraint](x T) {
    //s := T{}
    fmt.Printf("Hello %v", x)
}

func main() {
    t := Test{
        Name: "Test",
    }

    Print(t)
}

然而,如果我注释掉StructWithName并取消注释~struct块,那么它就可以编译通过。我无法理解两者之间的语义差异。

我尝试的是编写一个通用的方法,以一种通用的方式处理结构体;即x := S{},然后将其传递给外部库。在这种情况下,它是用于 Terraform 提供程序,资源中的代码非常相似,我对现有提供程序中看到的重复量感到有些困扰;在我的情况下,资源非常相似,只是在默认结构之上有一个或两个字段)。我希望能够编写一组通用方法来处理所有相似的内容,只在其他地方处理特定的内容(当然!)。

我在我的 Go 之旅中仍处于早期阶段,无法理解编译器错误的含义。

英文:

The following code does not compile, and reports ./main.go:35:7: Test does not satisfy Constraint (Test missing in main.StructWithName)

package main

import "fmt"

type Test struct {
	Name string
}

func (t Test) String() string {
	return fmt.Sprintf("Name: %v", t.Name)
}

type StructWithName struct {
	Name string
}

type Constraint interface {
	StructWithName
	// ~struct {
	// 	Name string
	// }
	String() string
}

func Print[T Constraint](x T) {
	//s := T{}
	fmt.Printf("Hello %v", x)
}

func main() {
	t := Test{
		Name: "Test",
	}

	Print(t)
}

However, if I comment out the StructWithName and uncomment the ~struct block, then it compiles fine. I can't wrap my hear around the semantic difference between both.

What I was trying to do was to have a generic method that could handle structs in a generic way; i.e. x := S{} then pass it along to an external library. In this case, it's for a Terraform provider, the code in the resources are very similar and I'm a bit troubled by the amount of repetition I see in exiting providers; in my case resources are extremely similar, some just have one or two fields on top of the default structure). I was hoping to be able to write a set of generic methods to do all that is similar and only specificities somewhere else (duh!).

I'm still early in my go journey and I can't make sense of the compiler error.

答案1

得分: 2

你实际上想要的,如果我理解正确的话,是不可能的。Go泛型不支持访问结构字段子集。

  • 参考链接:https://stackoverflow.com/questions/74770559/generic-function-to-set-field-of-different-structs-used-as-map-values/74771033#74771033

至于所讨论的错误...

类型的名称指定了类型的标识,具有不同名称的两个类型(它们不是彼此的别名)始终是不同的,因此TestStructWithName是两个不同的类型。它们唯一的共同之处是它们的底层类型。

type Constraint interface { StructWithName }接口是一个只包含一个类型StructWithName的类型集,由于Test不是该类型集的成员,这意味着使用Test类型无法满足该约束。

类型struct { Name string }是一个无名类型,任何无名类型的底层类型都是类型本身,即struct { Name string }的底层类型就是struct { Name string }

在约束中,类型前面的波浪符号,即~T,表示具有与T相同的底层类型的任何类型。或者更准确地说,

形式为~T的术语的类型集是所有底层类型为T的类型的集合。

因此,当你这样做时

type Constraint interface { ~struct { Name string } }

那么约束的类型集将包含任何具有struct { Name string }作为其底层类型的类型。

英文:

What you actually want, if I understood you correctly, is not possible. Go generics do not support access to struct field subsets.


As far as the error in question is concerned...

The name of a type specifies the type's identity and two types with different names (which are not aliases of each other) are always distinct, so Test and StructWithName are two distinct types. The only thing they have in common is their underlying type.

The type Constraint interface { StructWithName } interface is a type set that contains only one type, namely StructWithName, and since Test is not a member of that type set this means that it's impossible to satisfy that constraint with the type Test.

Type struct { Name string } is an unnamed type, the underlying type of any unnamed type is the type itself, i.e. the underlying type of struct { Name string } is struct { Name string }.

The tilde in front of a type in a constraint, i.e. ~T, means any type with underlying type identical to T. Or, more precisely,

> The type set of a term of the form ~T is the set of all types whose underlying type is T.

So when you do

type Constraint interface { ~struct { Name string } }

then the constraint's type set will contain any type that has struct { Name string } as its underlying type.

huangapple
  • 本文由 发表于 2023年7月17日 17:12:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76702988.html
匿名

发表评论

匿名网友

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

确定