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.
// 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.xfunciona. - Métodos e impls de trait do tipo embutido não são encaminhados.
Chame
p.base.greet()explicitamente. Playernão é subtipo deEntity. Passep.basequando uma função esperar umEntity.- 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.