Loading...
Loading...
Go interfaces, type assertions, type switches, and embedding from Effective Go. Covers implicit interface satisfaction, comma-ok idiom, generality through interface returns, interface and struct embedding for composition. Use when defining or implementing interfaces, using type assertions/switches, or composing types through embedding.
npx skill4agent add cxuu/golang-skills go-interfacesSource: Effective Go
implements// io.Writer interface - any type with this method satisfies it
type Writer interface {
Write(p []byte) (n int, err error)
}type ByteSlice []byte
// ByteSlice now implements io.Writer
func (p *ByteSlice) Write(data []byte) (n int, err error) {
*p = append(*p, data...)
return len(data), nil
}
// Can be used anywhere io.Writer is expected
var w io.Writer = &ByteSlice{}
fmt.Fprintf(w, "Hello, %s", "World")type Sequence []int
// Implements sort.Interface
func (s Sequence) Len() int { return len(s) }
func (s Sequence) Less(i, j int) bool { return s[i] < s[j] }
func (s Sequence) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// Implements fmt.Stringer
func (s Sequence) String() string {
sort.Sort(s)
return fmt.Sprint([]int(s))
}-erReaderWriterFormatterStringervalue.(typeName)typeNamevar w io.Writer = os.Stdout
f := w.(*os.File) // Extract *os.File from io.Writerstr, ok := value.(string)
if ok {
fmt.Printf("string value is: %q\n", str)
} else {
fmt.Printf("value is not a string\n")
}strokif _, ok := val.(json.Marshaler); ok {
fmt.Printf("value %v implements json.Marshaler\n", val)
}.(type)var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
fmt.Printf("unexpected type %T\n", t)
case bool:
fmt.Printf("boolean %t\n", t) // t has type bool
case int:
fmt.Printf("integer %d\n", t) // t has type int
case *bool:
fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}type Stringer interface {
String() string
}
var value interface{}
switch str := value.(type) {
case string:
return str // str is string
case Stringer:
return str.String() // str is Stringer
}// Good: Constructor returns interface type
func NewHash() hash.Hash32 {
return &myHash{} // unexported type
}
// The implementation is hidden; callers only see hash.Hash32crypto/ciphertype Block interface {
BlockSize() int
Encrypt(dst, src []byte)
Decrypt(dst, src []byte)
}
type Stream interface {
XORKeyStream(dst, src []byte)
}
// Returns Stream interface, hiding implementation details
func NewCTR(block Block, iv []byte) Streamtype Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// ReadWriter combines Reader and Writer
type ReadWriter interface {
Reader
Writer
}ReadWriterReaderWriter// bufio.ReadWriter embeds Reader and Writer
type ReadWriter struct {
*Reader // *bufio.Reader
*Writer // *bufio.Writer
}// Without embedding - tedious boilerplate
type ReadWriter struct {
reader *Reader
writer *Writer
}
func (rw *ReadWriter) Read(p []byte) (n int, err error) {
return rw.reader.Read(p)
}bufio.ReadWriterio.Readerio.Writerio.ReadWritertype Job struct {
Command string
*log.Logger
}
// Job now has Print, Printf, Println methods
job.Println("starting now...")// Access the embedded Logger directly
job.Logger.SetPrefix("Job: ")func (job *Job) Printf(format string, args ...interface{}) {
job.Logger.Printf("%q: %s", job.Command, fmt.Sprintf(format, args...))
}type ReadWriter struct {
*Reader
*Writer
}
// When rw.Read() is called, the receiver is the Reader, not ReadWriterXX// Verify *RawMessage implements json.Marshaler at compile time
var _ json.Marshaler = (*RawMessage)(nil)*RawMessagejson.Marshaler// In your package
type MyType struct { /* ... */ }
func (m *MyType) MarshalJSON() ([]byte, error) { /* ... */ }
// Compile-time check - fails if MarshalJSON signature is wrong
var _ json.Marshaler = (*MyType)(nil)Advisory: Go Wiki CodeReviewComments
time.Timeintstring// Value receiver: small, immutable type
type Point struct {
X, Y float64
}
func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
// Pointer receiver: method mutates receiver
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
// Pointer receiver: contains sync.Mutex
type Counter struct {
mu sync.Mutex
count int
}
func (c *Counter) Increment() {
c.mu.Lock()
c.count++
c.mu.Unlock()
}// Good: Consistent pointer receivers
type Buffer struct {
data []byte
}
func (b *Buffer) Write(p []byte) (int, error) { /* ... */ }
func (b *Buffer) Read(p []byte) (int, error) { /* ... */ }
func (b *Buffer) Len() int { return len(b.data) }
// Bad: Mixed receiver types
func (b Buffer) Len() int { return len(b.data) } // inconsistent| Concept | Pattern | Notes |
|---|---|---|
| Implicit implementation | Just implement the methods | No |
| Type assertion | | Panics if wrong type |
| Safe type assertion | | Returns zero value + false |
| Type switch | | Variable has correct type per case |
| Interface embedding | | Union of methods |
| Struct embedding | | Promotes T's methods |
| Access embedded field | | Type name is field name |
| Interface check | | Compile-time verification |
| Generality | Return interface from constructor | Hide implementation |