简体   繁体   中英

How can I define a struct field in my interface as a type constraint (type T has no field or method)?

I would like to make the following code compile. My understanding from reading the Type Parameters Proposal (Go Generics) is that this should work, but I must be missing something.

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
}

The error I get is:

./prog.go:7:8: Struct does not implement Type (possibly missing ~ for struct{A string} in constraint Type)./prog.go:11:23: vA undefined (interface Type has no method A)

I would like T to represent all structs with a particular field of a particular type. Adding ~ did not help.

Here's an example from the proposal that was implemented and is part of the latest Go beta release.

type structField interface {
    struct { a int; x int } |
        struct { b int; x float64 } |
        struct { c int; x uint64 }
}

https://go.dev/play/p/KZh2swZuD2m?v=gotip

Yes you are right, it should work, and it was mentioned in the proposal ( Composite types in constraints ):

For composite types [...] an operation may only be used if the operator accepts identical input types (if any) and produces identical result types for all of the types in the type set.

(...which means, among others, that using maps and slices together in a type set restricts the map type to map[int]T , as the index operator ( [] ) input type is int )

Field access when all fields have identical type should be included in this definition, but it was consciously left out of Go 1.18 implementation. The linked Go issue #48522 nicely lays out the expectations (it should work), the Go team's decision (they deem this feature not essential) and the workaround (using accessor methods).

The workaround boils down to the old boring interface-based polymorphism that we all have been using so far without type params:

type Type interface {
    GetA() string
}

func (s Struct) GetA() string {
    return s.A
}

And at this point you don't even have to use the Type interface as a constraint. It can just be a plain interface type:

func PrintA(v Type) {
    fmt.Printf("%s\n", v.GetA())
}

Partially related, I asked a similar question: How to constrain type parameter to structs that embed another struct? and the conclusion, for the time being, is basically the same as the one presented here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM