如何在我的接口中将结构字段定义为类型约束(类型 T 没有字段或方法)?
How can I define a struct field in my interface as a type constraint (type T has no field or method)?
我想编译以下代码。通过阅读类型参数提案(Go 泛型),我的理解是这应该可行,但我一定遗漏了一些东西。
package main
import "fmt"
func main() {
s := Struct{A: "Hello World!"}
PrintA(s)
}
func PrintA[T Type](v T) {
fmt.Printf("%s\n", v.A)
}
type Type interface {
struct{ A string }
}
type Struct struct {
A string
}
func (s Struct) String() string {
return s.A
}
我得到的错误是:
./prog.go:7:8: Struct does not implement Type (possibly missing ~ for struct{A string} in constraint Type)
./prog.go:11:23: v.A undefined (interface Type has no method A)
我希望 T
表示具有特定类型的特定字段的所有结构。添加 ~
没有帮助。
这是已实施提案中的一个示例,它是最新 Go 测试版的一部分。
type structField interface {
struct { a int; x int } |
struct { b int; x float64 } |
struct { c int; x uint64 }
}
Go 1.18 已完全禁用字段访问。 Go 1.18 release notes 提到这个:
The current generics implementation has the following known limitations:
[...]
- The Go compiler does not support accessing a struct field
x.f
where x
is of type parameter type even if all types in the type parameter's type set have a field f
. We may remove this restriction in Go 1.19.
任何结构类型的变通方法归结为我们迄今为止一直在使用的旧的、无聊的基于接口的多态性,而没有类型参数:
type Type interface {
GetA() string
}
func (s Struct) GetA() string {
return s.A
}
此时您甚至不必使用 Type
接口作为约束。它可以只是一个普通的接口类型:
func PrintA(v Type) {
fmt.Printf("%s\n", v.GetA())
}
旧答案
在 2022 年初的某个时候,当此功能仍在开发中时,如果您添加 ~
:
,您的示例确实有效
type Type interface {
~struct{ A string }
}
但 它仅适用于 完全 定义为 struct{ A string }
的结构,除此之外别无他法。定义一个约束“代表[s]具有特定类型的特定字段的所有结构”从来没有被支持过。有关详细信息,请参阅 。
相反,您从提案中引用的示例是关于访问类型集中的公共字段。通过定义结构的联合:
type structField interface {
~struct { a int; x int } | ~struct { a int; x float64 }
}
你应该能够访问这种类型参数的字段a
,但是这又没有实现,正如答案开头提到的.如果联合中的所有术语都具有相同的基础类型(示例改编自 issue #48522),它曾经有效:
package main
import "fmt"
type Point struct {
X, Y int
}
type Rect struct {
X, Y int
}
func GetX[P Point | Rect] (p P) int {
return p.X
}
func main() {
p := Point{1, 2}
r := Rect{2, 3}
fmt.Println("X: %d %d", GetX(p), GetX(r)) // prints X: 1 2
}
自 2022 年 3 月起,此代码不再编译。
我想编译以下代码。通过阅读类型参数提案(Go 泛型),我的理解是这应该可行,但我一定遗漏了一些东西。
package main
import "fmt"
func main() {
s := Struct{A: "Hello World!"}
PrintA(s)
}
func PrintA[T Type](v T) {
fmt.Printf("%s\n", v.A)
}
type Type interface {
struct{ A string }
}
type Struct struct {
A string
}
func (s Struct) String() string {
return s.A
}
我得到的错误是:
./prog.go:7:8: Struct does not implement Type (possibly missing ~ for struct{A string} in constraint Type) ./prog.go:11:23: v.A undefined (interface Type has no method A)
我希望 T
表示具有特定类型的特定字段的所有结构。添加 ~
没有帮助。
这是已实施提案中的一个示例,它是最新 Go 测试版的一部分。
type structField interface {
struct { a int; x int } |
struct { b int; x float64 } |
struct { c int; x uint64 }
}
Go 1.18 已完全禁用字段访问。 Go 1.18 release notes 提到这个:
The current generics implementation has the following known limitations:
[...]
- The Go compiler does not support accessing a struct field
x.f
wherex
is of type parameter type even if all types in the type parameter's type set have a fieldf
. We may remove this restriction in Go 1.19.
任何结构类型的变通方法归结为我们迄今为止一直在使用的旧的、无聊的基于接口的多态性,而没有类型参数:
type Type interface {
GetA() string
}
func (s Struct) GetA() string {
return s.A
}
此时您甚至不必使用 Type
接口作为约束。它可以只是一个普通的接口类型:
func PrintA(v Type) {
fmt.Printf("%s\n", v.GetA())
}
旧答案
在 2022 年初的某个时候,当此功能仍在开发中时,如果您添加 ~
:
type Type interface {
~struct{ A string }
}
但 它仅适用于 完全 定义为 struct{ A string }
的结构,除此之外别无他法。定义一个约束“代表[s]具有特定类型的特定字段的所有结构”从来没有被支持过。有关详细信息,请参阅
相反,您从提案中引用的示例是关于访问类型集中的公共字段。通过定义结构的联合:
type structField interface {
~struct { a int; x int } | ~struct { a int; x float64 }
}
你应该能够访问这种类型参数的字段a
,但是这又没有实现,正如答案开头提到的.如果联合中的所有术语都具有相同的基础类型(示例改编自 issue #48522),它曾经有效:
package main
import "fmt"
type Point struct {
X, Y int
}
type Rect struct {
X, Y int
}
func GetX[P Point | Rect] (p P) int {
return p.X
}
func main() {
p := Point{1, 2}
r := Rect{2, 3}
fmt.Println("X: %d %d", GetX(p), GetX(r)) // prints X: 1 2
}
自 2022 年 3 月起,此代码不再编译。