鲁斯特的印刷品如何!宏执行取消引用?



println!宏处理值和引用,而无需显式取消引用。

首先,创建一个向量

let v = vec![0, 2, 3, -4];
  1. 打印来自vec.iter的引用

    for x in v.iter() {
    println!("x: {}", x);
    }
    
  2. vec.iter打印取消参照的元素

    for x in v.iter() {
    println!("x: {}", *x);
    }
    
  3. 打印vec的值

    for x in v {
    println!("x: {}", x);
    }
    

案例 1 中的内部取消引用是如何完成的?

我知道内部println!进行了另一个宏调用,但链中的最后一个宏format_args!是在编译器级别实现的,我对它没有看法。

macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "n"), $($arg)*));
}
macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
}
macro_rules! format_args {
($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
}

源代码参考

这里重要的是,在格式字符串中使用{}会调用传递的值的Display特征。

正如预期的那样,i32 类型实现了Display,这就是允许您的情况 #2 和案例 #3 工作的原因。因为他们得到的是标准的i32值,而不是参考,所以这一切都有效。

对于您的情况#1,x将是一个&i32,这似乎是您问题的核心。答案就在Display特质中。显示内容包含以下内容:

impl<'a, T> Display for &'a T 
where
T: Display + ?Sized

它说"对于T的引用类型,如果T实现Display,则实现Display"。这意味着由于i32实现了Display,引用类型也自动实现它。

此处的编译器没有执行特殊类型处理。编译器实现的代码将该责任传递给Display特征的实现。

最新更新