Rust声明宏println剖析

        当我们用cargo new XXX创建一个rust项目时,默认都会生成main.rs文件,里面的代码就是println!("Hello, world!");用于向控制台打印Hello world。因此,我打算通过标准库源码对println宏的实现机制进行深入剖析。

        首先,看一下声明宏println!的实现源码:

#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}

可以看到,println宏间接调用了format_args_nl宏,先对打印的内容进行格式化,然后通过标准库io模块的_print方法进行打印。接下来,我们看一下format_args_nl宏的实现源码:

/// Same as `format_args`, but adds a newline in the end.
    #[unstable(
        feature = "format_args_nl",
        issue = "none",
        reason = "`format_args_nl` is only for internal \
                  language use and is subject to change"
    )]
    #[allow_internal_unstable(fmt_internals)]
    #[doc(hidden)]
    #[rustc_builtin_macro]
    #[macro_export]
    macro_rules! format_args_nl {
        ($fmt:expr) => {{ /* compiler built-in */ }};
        ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
    }

代码中可以看到,format_args_nl宏都是由编译器内在实现的,不是由标准库实现,对于编译器的实现我也不熟悉,就不深入讨论了。

        回过头看,看一下具体的标准库io模块的_print方法实现源码:

#[unstable(
    feature = "print_internals",
    reason = "implementation detail which may disappear or be replaced at any time",
    issue = "none"
)]
#[doc(hidden)]
#[cfg(not(test))]
pub fn _print(args: fmt::Arguments<'_>) {
    print_to(args, stdout, "stdout");
}

里面调用print_to方法,具体看代码:

/// Write `args` to the capture buffer if enabled and possible, or `global_s`
/// otherwise. `label` identifies the stream in a panic message.
///
/// This function is used to print error messages, so it takes extra
/// care to avoid causing a panic when `local_s` is unusable.
/// For instance, if the TLS key for the local stream is
/// already destroyed, or if the local stream is locked by another
/// thread, it will just fall back to the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
where
    T: Write,
{
    if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
        && OUTPUT_CAPTURE.try_with(|s| {
            // Note that we completely remove a local sink to write to in case
            // our printing recursively panics/prints, so the recursive
            // panic/print goes to the global sink instead of our local sink.
            s.take().map(|w| {
                let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
                s.set(Some(w));
            })
        }) == Ok(Some(()))
    {
        // Succesfully wrote to capture buffer.
        return;
    }

    if let Err(e) = global_s().write_fmt(args) {
        panic!("failed printing to {}: {}", label, e);
    }
}

这个方法的操作是:如果可能的话,把' args '写入到捕获缓冲区,否则写入到标准输出。

你可能感兴趣的:(Rust,rust,开发语言,后端)