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

Popular posts from this blog

java - Spring Data JPA: Why findOne(id) executing delete query internally? -

python - Mongodb How to add addtional information when aggregating? -

java - Incorrect order of records in M-M relationship in hibernate -