Saltar al contenido

Traits

En esta página

Un trait declara un conjunto de firmas que cualquier tipo puede satisfacer. La definición no incluye datos — solo la interfaz. Varios traits independientes describen comportamientos ortogonales:

Displayable y Shape son dos traits; Square implementa ambos con cuerpos 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 proporciona el cuerpo de cada método exigido por el trait. Tipos distintos tienen implementaciones independientes — cada uno resuelve la misma interfaz a su manera:

Circle y Rectangle implementan HasArea de forma independiente.

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

Un trait puede incluir métodos por defecto — con cuerpo ya definido en la declaración del trait. El implementador puede aceptar el valor por defecto o sobreescribirlo:

Person usa el comportamiento por defecto de hello; Pet lo reemplaza por un saludo personalizado.

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?

Un mismo tipo puede satisfacer múltiples traits al mismo tiempo, cada uno en su propio bloque impl Trait for Type. Los métodos de todos los traits quedan disponibles en la instancia:

Circle implementa HasArea, Named y Describabledescribe combina los otros dos.

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

Desafío

Crea un trait Resizable con un método scale(self, factor: float) -> Self. Impleméntalo para Circle y Rectangle de los ejemplos anteriores.

Buscar en Zolo

9 resultados

enespt-br