[][src]Attribute Macro proconio_derive::fastout

#[fastout]

Enables buffering for stdout.

You cannot create a closure containing print! or println! in #[fastout] function. This is because the closure cannot implement Send since StdoutLock, which is not a Send, is internally captured into the closure. This causes a trait bound mismatch when used with function requiring its argument closure to be a Send, such as std::thread::spawn().

This example deliberately fails to compile
use proconio::fastout;

use std::thread;

#[fastout]
fn main() {
   thread::Builder::new()
       .stack_size(32 * 1024 * 1024)
       .spawn(|| {
           println!("Hi!");
       })
       .unwrap()
       .join()
       .unwrap();
}

It is too conservative to make all of such closures compilation error because it is actually no problem to use such a closure only inside a single thread. However, since trait bound check is done after macro expansions, there is no way to check whther the closure is required to be a Send or not. And the compiler error message for actual mismatch of a Send requirement is too confusing, pointing out codes you didn't write (macro-expanded codes) as an error position. In conclusion, for user-friendliness, all of them are prohibited for now.

Internally this is the same with

let __proconio_stdout = ::std::io::stdout();
let mut __proconio_stdout = ::std::io::BufWriter::new(__proconio_stdout.lock());

#[allow(unused_macros)]
macro_rules! print {
    ($($tt:tt)*) => {{
        use std::io::Write as _;
        ::std::write!(__proconio_stdout, $($tt)*).unwrap();
    }};
}

#[allow(unused_macros)]
macro_rules! println {
    ($($tt:tt)*) => {{
        use std::io::Write as _;
        ::std::writeln!(__proconio_stdout, $($tt)*).unwrap();
    }};
}

let __proconio_res = {
    // Your code goes here
};
<::std::io::BufWriter<::std::io::StdoutLock> as ::std::io::Write>::flush(
    &mut __proconio_stdout
).unwrap();
return __proconio_res;