Pular para o conteúdo

Embutimento de Campos com `using`

Nesta página

using embute um struct dentro de outro e promove os campos do struct embutido para o acesso por ponto do struct externo. Pense como "acesso flat sem cópia": p.x significa p.base.x.

Embed nomeado, embed anônimo, shadowing outer-wins, cadeias transitivas e a regra de sem-subtipagem.

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

}

Embed nomeado vs anônimo

// Nomeado — você escolhe o nome do campo.
struct Player {
  using base: Entity,
  hp: int,
}

// Anônimo — o nome do campo é o último segmento do tipo, em minúsculas.
struct Particle {
  using Vec2,   // nome implícito do campo: vec2
  mass: int,
}

A construção sempre usa o nome real do campo:

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

O que é (e não é) promovido

  • Campos do tipo embutido são promovidos — p.x funciona.
  • Métodos e impls de trait do tipo embutido não são encaminhados. Chame p.base.greet() explicitamente.
  • Player não é subtipo de Entity. Passe p.base quando uma função esperar um Entity.
  • A promoção só se aplica a receptores estaticamente tipados (let p: Player = ..., parâmetros, self, literais de struct). Receptores sem tipo explícito não são reescritos.

Prioridade e ambiguidade

Um campo externo sempre sobrepõe um campo promovido de mesmo nome:

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

Se dois campos using promovem o mesmo nome sem um campo externo que resolva o empate, o compilador emite TE112. Qualifique o acesso explicitamente: d.left.value ou d.right.value.

Embutimento transitivo

A promoção encadeia por múltiplos níveis 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

Erros

Código Significado
TE112 Dois campos using promovem o mesmo nome — qualifique o acesso.
TE113 O tipo do campo using não é um struct (ex: using base: int).

Nota sobre LSP

Hover e go-to-definition em um campo promovido (ex: p.x) atualmente não retornam nenhum resultado — o LSP não executa o passo de desugar do using, portanto não reconhece acessos a campos promovidos. Use a forma qualificada p.base.x no editor para obter hover e navegação. Suporte completo a campos promovidos no IDE é uma melhoria conhecida para o futuro.

Veja também

Buscar no Zolo

9 resultados

enespt-br