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.
// 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.xfunciona. - Los métodos e impls de trait del tipo incrustado no se reenvían.
Llama a
p.base.greet()explícitamente. Playerno es subtipo deEntity. Pasap.basecuando una función espere unEntity.- 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.