Interfaces
An interface is a set of method signatures. A type satisfies an interface by implementing all its methods. No explicit declaration is needed.
interface Shape { fn area() -> int}
struct Rectangle { width: int, height: int,}
Rectangle implements area() so it satisfies Shapeimpl Rectangle { fn area(self) -> int { self.width * self.height }}
fn describe(shape: Shape) -> string { f"area is {shape.area()}"}
describe(Rectangle { width: 10, height: 5 })Rectangle is accepted as a ShapeEmbedding
Section titled “Embedding”An interface can embed other interfaces, composing their methods into one:
interface Reader { fn read(buf: Slice<byte>) -> Result<int, error>}
interface Writer { fn write(buf: Slice<byte>) -> Result<int, error>}
satisfied only by a type with both read() and write()interface ReadWriter { embed Reader embed Writer}Generic interfaces
Section titled “Generic interfaces”Interfaces accept type parameters:
interface Iterator<T> { fn next() -> Option<T>}
struct Counter { current: int, end: int,}
satisfies Iterator<T>impl Counter { fn next(self: mut Ref<Counter>) -> Option<int> { if self.current >= self.end { return None } let value = self.current self.current += 1 Some(value) }}Exact type arguments
Section titled “Exact type arguments”Type arguments must match exactly, as in Go. Even if Cat satisfies Animal, a Box<Cat> is not a Box<Animal>.
interface Animal { fn speak() -> string}
struct Box<T> { value: T,}
impl<T> Box<T> { fn get(self) -> T { self.value }}
fn take_box(box: Box<Animal>) { let _ = box.get()}
struct Cat {}
impl Cat { fn speak(self) -> string { "meow" }}
let cat_box = Box { value: Cat {} }take_box(cat_box)error: expected Box<Animal>, found Box<Cat>Mixed collections
Section titled “Mixed collections”A Slice<Animal> can hold a mix of different types, so long as each one satisfies Animal:
struct Dog {}
impl Dog { fn speak(self) -> string { "woof" }}
let pets: Slice<Animal> = [Cat {}, Dog {}]A bound does the opposite. Every element must be the same concrete type:
fn speak_all<T: Animal>(pets: Slice<T>) -> string { pets.fold("", |sounds, pet| sounds + pet.speak())}
let cats = [Cat {}, Cat {}]speak_all(cats)T is CatNil Go interfaces
Section titled “Nil Go interfaces”A Go interface holds a type and a value, so it has three states, not two:
var p *MyHandler = nilvar h1 http.Handleruntyped nilvar h2 http.Handler = ptyped nilvar h3 http.Handler = &MyHandler{}non-nilA literal encoding would distinguish all three:
match handler { None => fmt.Println("untyped nil"), Some(None) => fmt.Println("typed nil"), Some(Some(h)) => h.ServeHTTP(w, r),}Lisette collapses both typed nil and untyped nil into None. Neither state holds a value, and a method call on either panics once it touches the receiver. Go allows one exception: a method that never reads through its receiver runs on a typed nil. Lisette treats this exception as too rare in practice to model.
match handler { Some(h) => h.ServeHTTP(w, r), None => fmt.Println("no handler"),}