Module lessons (1/5)
Interfaces: defining a behavior
An interface in Go is a set of method signatures. A value
implements the interface if it has all those methods — no
implements, no extends, no explicit registration. It's the
model often called "structural typing" or "static duck typing":
the compiler checks conformance at compile time, but based on
shape, not on declarations.
Declaring an interface
type Greeter interface {
Greet() string
}Convention: names ending in -er for single-method interfaces
(Reader, Writer, Stringer, Closer). Small interfaces
(1–2 methods) are idiomatic: the standard library is full of
tiny interfaces that compose together (io.ReadWriter,
io.ReadCloser, …).
Implicit implementation
type Person struct{ Name string }
func (p Person) Greet() string {
return "ciao " + p.Name
}
// Person satisfies Greeter because it has the required method.
var s Greeter = Person{Name: "Ada"}
fmt.Println(s.Greet())No keyword. If the type has the methods, it can be assigned to a variable of that interface type. That's it.
Polymorphism via interface
type Robot struct{ ID string }
func (r Robot) Greet() string { return "bip " + r.ID }
func greet(s Greeter) {
fmt.Println(s.Greet())
}
greet(Person{Name: "Ada"})
greet(Robot{ID: "R2"})greet accepts any type that satisfies Greeter. This is the Go way
of doing polymorphism: no hierarchies, just capability.
The empty interface
var x interface{} = 42
var y any = "ciao" // any is the built-in alias of interface{}interface{} (or any since Go 1.18) requires no methods, so any
value satisfies it. Useful for generic containers, but to extract
the concrete value you need a type assertion or type switch
(next lessons).
Method set: value vs pointer receiver (preview)
Recall from Module 5:
- Methods with a value receiver are in the method set of both
Tand*T. - Methods with a pointer receiver are ONLY in the method set of
*T.
Practical consequence:
type Counter struct{ N int }
func (c *Counter) Inc() { c.N++ }
type Incrementer interface { Inc() }
var i Incrementer = &Counter{} // OK: *Counter has Inc()
// var j Incrementer = Counter{} // ERROR: Counter (value) does NOTWhen a method has a pointer receiver, you must assign a pointer to the interface variable.
Try it
Define an interface Greeter with a single method Greet() string.
Show hint
Syntax: `type Name interface { Method(args) return }`.
Solution available after 3 attempts
Implement Greeter on a new type Robot with field ID string; the method returns 'bip ' + ID.
Show hint
No `implements`: just define the method with the right signature.
Solution available after 3 attempts
How do you declare that type P implements the Greeter interface?
type P struct{}
// ?Recap
- Interface = set of method signatures; no
implements. - Implicit implementation: just have the methods with the right signature.
- Idiomatic: small interfaces (1–2 methods), names in
-er. interface{}/any: accepts any value, loses type safety.- Method set: pointer receiver → only
*Tsatisfies the interface. - Go polymorphism: interface-typed parameters, no hierarchies.