Eu esperava que o código a seguir não compilasse, mas ele compilou ( playground ):
fn main() {
(0..3)
.map(|i| {
struct S {
v: usize,
}
S { v: i }
})
.collect::<Vec<_>>();
}
Pensei que cada chamada de fechamento definiria um novo tipo de struct (e sua instância), então o resultado não poderia ser coletado como um vetor de algum tipo único, mas parece que S
não é tão local.
Como isso funciona exatamente nos bastidores? Quero uma explicação rigorosa, como um link para uma página de The Rust Reference , então adicionei #language-lawyer
uma tag.
Se você literalmente ler o código acima sem saber como o Rust funciona, acho que pode haver duas interpretações, como mostrado abaixo. Achei que a segunda interpretação estava correta, mas o fato de o código compilar implica que a primeira está correta. Mas por quê? Essa é a minha pergunta.
Interpretação 1
//`S` is *global* in some sense.
struct S {
v: usize,
}
//Every invocation of the closure just creates a new instance of the type `S`.
for i in 0..3 {
vec.push(S { v: 0 });
}
Interpretação 2
{
//Every invocation of the closure declares a new struct type
// which is local to the invocation.
struct __S_anonymous_01 {
v: usize,
}
//And it then creates a new instance of that type.
vec.push(__S_anonymous_01 { v: 0 });
}
{
struct __S_anonymous_02 {
v: usize,
}
vec.push(__S_anonymous_02 { v: 1 });
}
{
struct __S_anonymous_03 {
v: usize,
}
vec.push(__S_anonymous_03 { v: 2 });
}
//And `__S_anonymous_{01|02|03}` are all different
// though they have the same structure
// because Rust doesn't support duck typing.
https://doc.rust-lang.org/stable/reference/items.html
(Os itens incluem estruturas).
Geralmente, rust não define tipos dependentes de valor. Além disso, itens (incluindo, por exemplo, structs e funções) definidos dentro de funções/fechamentos não podem usar valores (por exemplo, variáveis) ou mesmo parâmetros genéricos de seus pais, o que reforça o fato de que ser aninhado para itens não impacta nada além da visibilidade.