println!
宏处理值和引用,而无需显式取消引用。
首先,创建一个向量
let v = vec![0, 2, 3, -4];
打印来自
vec.iter
的引用for x in v.iter() { println!("x: {}", x); }
从
vec.iter
打印取消参照的元素for x in v.iter() { println!("x: {}", *x); }
打印
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
特征的实现。