rust - Can I pass the same mutable trait object in multiple iterations of a loop without adding indirection? -
i'm writing bit of code can either output stdout or file. based on external condition, instantiate file or stdout , create trait object reference appropriate item:
use std::{io,fs}; fn write_it<w>(mut w: w) w: io::write { } fn main() { let mut stdout; let mut file; let t: &mut io::write = if true { stdout = io::stdout(); &mut stdout } else { file = fs::file::create("/tmp/output").unwrap(); &mut file }; _ in 0..10 { write_it(t); } } this works fine, until try call write_it multiple times. fail, t moved write_it , not available on subsequent iterations of loop:
<anon>:18:18: 18:19 error: use of moved value: `t` <anon>:18 write_it(t); ^ note: `t` moved here because has type `&mut std::io::write`, non-copyable i can work around adding layer of indirection:
let mut t: &mut io::write; write_it(&mut t); but seems potentially inefficient. inefficient? there cleaner way of writing code?
you'll need explicitly reborrow:
for _ in 0..10 { write_it(&mut *t); } one sees happen implicitly, not in case because write_it takes raw generic, w, , compiler implicitly reborrows &mut when used in place expecting &mut. e.g. if was
fn write_it<w: ?sized + write>(w: &mut w) { ... } your code works fine, since explicit &mut in type of argument ensure compiler implicitly reborrow shorter lifetime (i.e. &mut*).
cases demonstrate &mut in fact move ownership, implicit reborrowing disguises in favour of improved ergonomics.
as performance of version reference: speed of &mut (&mut write) indistinguishable plain &mut write: virtual call more expensive dereferencing &mut.
furthermore, aliasing guarantees of &mut means compiler free how interacts &mut: e.g., depending on internals, may load 2 words of &mut write pointer registers once @ start of write_it , write changes @ end. legal because being &mut means there's nothing else can mutate memory.
lastly, @ moment, "large" value &mut write passed via pointer; same &mut &mut write on machine. assembly both &mut *t , &mut t versions both start (literally difference can see names of ltmp... labels):
_zn8write_it20h2919620193267806634e: .cfi_startproc cmpq %fs:112, %rsp ja .lbb4_2 movabsq $72, %r10 movabsq $0, %r11 callq __morestack retq .lbb4_2: pushq %r14 .ltmp116: .cfi_def_cfa_offset 16 pushq %rbx .ltmp117: .cfi_def_cfa_offset 24 subq $56, %rsp .ltmp118: .cfi_def_cfa_offset 80 .ltmp119: .cfi_offset %rbx, -24 .ltmp120: .cfi_offset %r14, -16 movq (%rdi), %rsi movq 8(%rdi), %rax ... the 2 movqs @ end loading 2 words of &mut write trait object registers.
Comments
Post a Comment