Last active
May 6, 2026 05:31
-
-
Save Integralist/bb059e61e1551fa54ac7c7576cbc613d to your computer and use it in GitHub Desktop.
Go: unexported interface methods "seal" the interface support when embedding types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This code demonstrates how you can embed a type, | |
| // and have it satisfy an interface (`ProblemDetailer`) | |
| // but only for the embedded type. | |
| // This works because the interface uses an unexported method, | |
| // that is part of the embedded type's package. | |
| // https://go.dev/play/p/7lbikIyPHi1 | |
| // | |
| // IMPORTANT: If the `isProblem` inteface method was exported (i.e `IsProblem`), | |
| // then our `Fake` struct would pass the `.(errorsx.ProblemDetailer)` type assertion | |
| // e.g. https://go.dev/play/p/pPD3OgtiyHx | |
| package main | |
| import ( | |
| "fmt" | |
| "play.ground/errorsx" | |
| ) | |
| // Embeds Problem — should satisfy ProblemDetailer via promoted method. | |
| type OrderProblem struct { | |
| errorsx.Problem | |
| OrderID string | |
| } | |
| // Independently defines isProblem() — should NOT satisfy ProblemDetailer | |
| // because unexported methods are package-scoped. | |
| type Fake struct{} | |
| func (Fake) isProblem() {} | |
| func main() { | |
| // 1. Pointer to Problem | |
| var p any = &errorsx.Problem{} | |
| _, ok := p.(errorsx.ProblemDetailer) | |
| fmt.Printf("*Problem satisfies ProblemDetailer: %v\n", ok) | |
| // 2. Value Problem | |
| var v any = errorsx.Problem{} | |
| _, ok = v.(errorsx.ProblemDetailer) | |
| fmt.Printf(" Problem satisfies ProblemDetailer: %v\n", ok) | |
| // 3. Pointer to embedding type | |
| var op any = &OrderProblem{} | |
| _, ok = op.(errorsx.ProblemDetailer) | |
| fmt.Printf("*OrderProblem satisfies ProblemDetailer: %v\n", ok) | |
| // 4. Value embedding type | |
| var ov any = OrderProblem{} | |
| _, ok = ov.(errorsx.ProblemDetailer) | |
| fmt.Printf(" OrderProblem satisfies ProblemDetailer: %v\n", ok) | |
| // 5. Fake with its own isProblem() — different package identity | |
| var f any = Fake{} | |
| _, ok = f.(errorsx.ProblemDetailer) | |
| fmt.Printf(" Fake satisfies ProblemDetailer: %v\n", ok) | |
| // 6. Pointer to Fake | |
| var fp any = &Fake{} | |
| _, ok = fp.(errorsx.ProblemDetailer) | |
| fmt.Printf("*Fake satisfies ProblemDetailer: %v\n", ok) | |
| } | |
| -- go.mod -- | |
| module play.ground | |
| go 1.21 | |
| -- errorsx/errorsx.go -- | |
| package errorsx | |
| // ProblemDetailer identifies RFC 7807 Problem Details payloads. | |
| // Unexported method seals the interface — only types embedding | |
| // Problem (or defined in this package) can satisfy it. | |
| type ProblemDetailer interface { | |
| isProblem() | |
| } | |
| type Problem struct { | |
| Title string | |
| Detail string | |
| } | |
| // Value receiver: both Problem and *Problem satisfy ProblemDetailer. | |
| func (Problem) isProblem() {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment