The Shape Interface
An interface in Go is a list of method signatures:
type Shape interface {
Area() float64
Perimeter() float64
}
A type satisfies it by having those methods. There is no implements, no
registration, and nothing in Rect mentions Shape. The compiler checks the
match where the value is used - assigned to a Shape variable, passed to a
Shape parameter, appended to a []Shape - and that is the only place the
relationship exists.
That inversion matters: the interface belongs to the code that consumes it, not to the types that satisfy it. You can write an interface for a type you did not write, in your own package, after the fact.
Two values, one variable
An interface value holds two things: the concrete type, and the value of that
type. var s Shape = Rect{2, 3} records "this is a Rect" beside the Rect
itself. Calling s.Area() looks up Rect's Area and runs it, so the same
line of code does different work depending on what is in there.
The zero value of an interface is nil: no type, no value. Calling a method on
it panics, so a function that returns "nothing" as an interface returns nil
and callers check for it.
Asking what is inside
A type assertion recovers the concrete value, and the comma-ok form asks rather than insists:
r, ok := s.(Rect) // ok is false if s does not hold a Rect
The same syntax works with another interface on the right, which asks whether the value has that method set as well:
if n, ok := s.(Named); ok {
fmt.Println(n.Name())
}
Without , ok, a failed assertion panics. Use the two-value form unless you can
prove the assertion holds.
Small interfaces
The interfaces you meet in the standard library are one or two methods:
io.Reader,
io.Writer,
fmt.Stringer, error. Small interfaces are
easy to satisfy by accident, which is exactly the point - a type written years
ago fits a function written today. Start with the smallest set of methods your
function actually calls.
Task
Implement Area and Perimeter on Rect and Circle, Name on Circle,
then the four functions that work through the interface: TotalArea,
Largest, Describe and CountAtLeast.
Hints
math.Piis the constant;Circle{R: 2}has an area of4 * math.Pi.Largeststarts withvar best Shape. The zero value of an interface isnil, so an empty slice returnsnilwithout a special case.Describeneedsif n, ok := s.(Named); ok- a plains.(Named)would panic on aRect, which has noNamemethod.%.2fformats both numbers.Circle{R: 1}describes ascircle: area 3.14, perimeter 6.28.CountAtLeastis inclusive: an area exactly equal tomincounts.