Eu estava analisando esta questão em relação à resposta a um problema simples que tenho: quero ter um bloco if/else para decidir se uma iteração deve ter uma barra de progresso tqdm acompanhante :
fn run(n: usize, verbose: bool) {
let it = if verbose { tqdm(0..n) } else { 0..n };
for _ in it { _ }
}
O código acima não compila, porque os dois braços do if/else têm tipos diferentes, um é a Range
e o outro é a Tqdm<Range>
. No entanto, com base na pergunta vinculada no topo, fiz a seguinte modificação e ele compila bem:
fn run(n: usize, verbose: bool) {
let it: Box<dyn impl Iterator<Item = usize>> = if verbose {
Box::new(tqdm(0..n))
} else {
Box::new(0..n)
};
for _ in it { _ }
}
Ao especificar o tipo (na verdade, isso é necessário, apenas envolvê-lo Box
não ajuda), posso fazer o código compilar. No entanto, ingenuamente sinto que isso significa que há uma alocação extra de heap do dyn Iterator
objeto, enquanto antes tudo (pelo menos como eu entendo) era mais ou menos manipulado dentro do quadro de pilha. Sei que, em geral, o despacho dinâmico (que eu acho que é, mas não tenho certeza absoluta) vem com um impacto no desempenho.
Antes de embrulhar, Box
tentei apenas anotar, dyn Iterator<Item = usize>
mas não funcionou. Acho que porque, de alguma forma, a Box
abstração é necessária, mas não entendi bem o porquê.
Existe uma maneira de fazer esse código, ou a ideia por trás dele, compilar sem o Box
e a alocação de heap? Isso é menos importante do que eu penso? Se isso é impossível, por que não posso fazer o simples dyn Iterator
sem o Box
como mencionei acima?
Você está correto, isso
Box<_>
resultaria em uma alocação e issodyn
resultaria em despacho dinâmico.Uma alternativa sem alocação para
Box<dyn _>
is&dyn _
(como suadyn
ideia simples, mas com a sintaxe correta), mas que precisa ser emprestada de um local que permaneça no escopo (fora dos blocosif
ouelse
):Se você precisasse retornar o iterador, a abordagem acima não funcionaria, pois você não pode retornar referências a variáveis locais. Em vez disso, você poderia usar a seguinte construção, que também evita
dyn
: