Pular para o conteúdo

Traits

Nesta página

Um trait declara um conjunto de assinaturas que qualquer tipo pode satisfazer. A definição não inclui dados — apenas a interface. Vários traits independentes descrevem comportamentos ortogonais:

Displayable e Shape são dois traits; Square implementa ambos com corpos separados.

06-trait-definition.zolo
Playground
// Feature: Trait definition — shared interface

// Syntax: `trait Name { fn method(self) -> Ret  /* no body */ }`

// When to use: describe a set of methods that multiple types will

// implement (ad-hoc polymorphism).


// Trait without defaults — only signatures. Each implementer is

// required to provide a body for `display`.

trait Displayable {
  fn display(self) -> str
}

// Trait with multiple signatures.

trait Shape {
  fn area(self) -> float

  fn name(self) -> str
}

struct Square {
  side: float,
}

impl Displayable for Square {
  fn display(self) -> str {
    return "Square({self.side})"
  }
}

impl Shape for Square {
  fn area(self) -> float {
    return self.side * self.side
  }

  fn name(self) -> str {
    return "square"
  }
}

let s = Square { side: 4.0 }
print(s.display())  // Square(4)

print(s.area())  // 16

print(s.name())  // square

// expected:

// Square(4)

// 16

// square

impl Trait for Type fornece o corpo de cada método exigido pelo trait. Tipos distintos têm implementações independentes — cada um resolve a mesma interface de forma própria:

Circle e Rectangle implementam HasArea de forma independente.

07-trait-implementation.zolo
Playground
// Feature: Trait implementation — `impl Trait for Type`

// Syntax: `impl Trait for Type { fn method(self) { ... } }`

// When to use: declare that a concrete type satisfies a trait by

// providing the body for each required method.


trait HasArea {
  fn area(self) -> float
}

struct Circle {
  radius: float,
}

struct Rectangle {
  width: float,
  height: float,
}

// Each `impl Trait for Type` is independent.

impl HasArea for Circle {
  fn area(self) -> float {
    return 3.14159 * self.radius * self.radius
  }
}

impl HasArea for Rectangle {
  fn area(self) -> float {
    return self.width * self.height
  }
}

let c = Circle { radius: 5.0 }
let r = Rectangle { width: 3.0, height: 4.0 }

// The `area` method resolves correctly for each type.

print(c.area())  // 78.53975

print(r.area())  // 12

// expected:

// 78.53975

// 12

Um trait pode incluir métodos padrão — com corpo já definido na declaração do trait. O implementador pode aceitar o padrão ou sobrescrevê-lo:

Person usa o comportamento padrão de hello; Pet o substitui por uma saudação personalizada.

08-trait-default-impl.zolo
Playground
// Feature: Default implementation in traits

// Syntax: inside the `trait`, the fn already has a body `{ ... }`

// When to use: provide default behavior derived from other trait

// methods. Implementers can accept the default or override it in

// `impl Trait for Type`.

//

// Note: the checker resolves methods by looking at the type's

// `impl`. To use the default, we still copy the delegated call —

// that is, `impl` must list ALL trait methods. Here we show

// override and explicit delegation.


trait Greet {
  fn name(self) -> str
  // Default — implementers MAY redefine.



  fn hello(self) -> str {
    return "Hello, {self.name()}!"
  }
}

struct Person {
  full: str,
}

// Accepts the default — copies the body in the impl.

impl Greet for Person {
  fn name(self) -> str {
    return self.full
  }

  fn hello(self) -> str {
    return "Hello, {self.name()}!"
  }
}

struct Pet {
  nickname: str,
}

// Overrides the default with something specific.

impl Greet for Pet {
  fn name(self) -> str {
    return self.nickname
  }

  fn hello(self) -> str {
    return "Hi {self.nickname}, who's a good one?"
  }
}

let alice = Person { full: "Alice" }
let rex = Pet { nickname: "Rex" }

print(alice.hello())  // Hello, Alice!

print(rex.hello())  // Hi Rex, who's a good one?

// expected:

// Hello, Alice!

// Hi Rex, who's a good one?

Um mesmo tipo pode satisfazer múltiplos traits ao mesmo tempo, cada um em seu próprio bloco impl Trait for Type. Os métodos de todos os traits ficam disponíveis na instância:

Circle implementa HasArea, Named e Describabledescribe combina os outros dois.

09-multiple-traits.zolo
Playground
// Feature: Multiple traits on the same type

// Syntax: several independent `impl Trait for Type`

// When to use: combine orthogonal behaviors — the type satisfies

// each trait separately.


trait HasArea {
  fn area(self) -> float
}

trait Named {
  fn name(self) -> str
}

trait Describable {
  fn describe(self) -> str
}

struct Circle {
  radius: float,
}

impl HasArea for Circle {
  fn area(self) -> float {
    return 3.14159 * self.radius * self.radius
  }
}

impl Named for Circle {
  fn name(self) -> str {
    return "circle"
  }
}

impl Describable for Circle {
  fn describe(self) -> str {
    return "{self.name()} of area {self.area()}"
  }
}

let c = Circle { radius: 2.0 }
print(c.area())  // 12.56636

print(c.name())  // circle

print(c.describe())  // circle of area 12.56636

Desafio

Crie um trait Resizable com um método scale(self, factor: float) -> Self. Implemente-o para Circle e Rectangle dos exemplos acima.

Buscar no Zolo

9 resultados

enespt-br