Saltar al contenido

Incrustación de Campos con `using`

En esta página

using incrusta un struct dentro de otro y promueve los campos del struct incrustado al acceso por punto del struct externo. Piénsalo como "acceso plano sin copia": p.x significa p.base.x.

Incrustación nombrada, anónima, shadowing outer-wins, cadenas transitivas y la regla de no-subtipado.

14-using-embed.zolo
Playground
// Feature: using field embedding

// Syntax: `using base: Type` (named) or `using Type` (anonymous)

// Effect: promotes the embedded struct's fields into the outer struct's dot-access.

// FIELD-ONLY: methods of the embedded type are NOT forwarded.


// ---------- Struct definitions ----------


struct Entity {
  x: int,
  y: int,
}

struct Player {
  using base: Entity,
  hp: int,
}

struct Vec2 {
  x: int,
  y: int,
}

struct Particle {
  using Vec2,        // anonymous embed — implicit field name: vec2

  mass: int,
}

struct Base {
  name: str,
}

struct Derived {
  using base: Base,
  name: str,         // outer field shadows the promoted one

}

struct A { v: int }
struct B { using a: A }
struct C { using b: B }

// `using` also works in the compact (positional) struct form, including the

// inline method block: `self.x` here promotes through the `base` embed.

struct Sprite(using base: Entity, tag: str) {
  fn label(self) -> str { return "{self.tag}@{self.x},{self.y}" }
}

fn teleport(e: Entity) {
  print("{e.x},{e.y}")
}

fn main() {
  // ---------- named embed ----------

  let p = Player { base: Entity { x: 10, y: 20 }, hp: 100 }

  // Promoted field access — p.x desugars to p.base.x.

  print(p.x)    // 10

  print(p.y)    // 20

  print(p.hp)   // 100


  // The embed field is also reachable directly.

  print(p.base.x)  // 10


  // ---------- anonymous embed ----------

  let q = Particle { vec2: Vec2 { x: 3, y: 4 }, mass: 5 }
  print(q.x)      // 3  — promoted from q.vec2.x

  print(q.mass)   // 5


  // ---------- outer field wins ----------

  let d = Derived { base: Base { name: "base" }, name: "outer" }
  print(d.name)        // outer  (outer field wins)

  print(d.base.name)   // base


  // ---------- transitive ----------

  let c = C { b: B { a: A { v: 42 } } }
  print(c.v)   // 42  — promoted through B then C


  // ---------- compact (positional) form ----------

  let s = Sprite { base: Entity { x: 1, y: 2 }, tag: "hero" }
  print(s.x)          // 1      — promoted from s.base.x

  print(s.label())    // hero@1,2  — `self.x` promoted inside compact method


  // ---------- no subtyping ----------

  // Player cannot be passed where Entity is expected.

  // Pass p.base explicitly when Entity is required.

  teleport(p.base)   // 10,20

}

Incrustación nombrada vs anónima

// Nombrada — tú eliges el nombre del campo.
struct Player {
  using base: Entity,
  hp: int,
}

// Anónima — el nombre del campo es el último segmento del tipo, en minúsculas.
struct Particle {
  using Vec2,   // nombre implícito del campo: vec2
  mass: int,
}

La construcción siempre usa el nombre real del campo:

let p = Player { base: Entity { x: 0, y: 0 }, hp: 100 }
let q = Particle { vec2: Vec2 { x: 1, y: 2 }, mass: 3 }

Qué se promueve (y qué no)

  • Los campos del tipo incrustado se promueven — p.x funciona.
  • Los métodos e impls de trait del tipo incrustado no se reenvían. Llama a p.base.greet() explícitamente.
  • Player no es subtipo de Entity. Pasa p.base cuando una función espere un Entity.
  • La promoción solo se aplica a receptores estáticamente tipados (let p: Player = ..., parámetros, self, literales de struct). Los receptores sin tipo explícito no se reescriben.

Prioridad y ambigüedad

Un campo externo siempre sombrea un campo promovido del mismo nombre:

struct Derived {
  using base: Base,
  name: str,   // gana sobre Base.name
}

Si dos campos using promueven el mismo nombre sin un campo externo que resuelva el empate, el compilador emite TE112. Califica el acceso explícitamente: d.left.value o d.right.value.

Incrustación transitiva

La promoción encadena a través de múltiples niveles de using:

struct A { v: int }
struct B { using a: A }
struct C { using b: B }

let c = C { b: B { a: A { v: 42 } } }
print(c.v)   // 42

Errores

Código Significado
TE112 Dos campos using promueven el mismo nombre — califica el acceso.
TE113 El tipo del campo using no es un struct (ej: using base: int).

Nota sobre LSP

Hover y go-to-definition sobre un campo promovido (ej: p.x) actualmente no devuelven ningún resultado — el LSP no ejecuta el paso de desugar de using, por lo que no reconoce los accesos a campos promovidos. Usa la forma calificada p.base.x en el editor para obtener hover y navegación. El soporte completo de campos promovidos en el IDE es una mejora conocida para el futuro.

Consulta también

Buscar en Zolo

9 resultados

enespt-br