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
的引用类型,如果 Display
实现了 T
,则实现 Display
”。这意味着因为 i32
实现了 Display
,所以引用类型也会自动实现它。
编译器在这里没有进行特殊的类型处理。编译器实现的代码将该责任传递给
Display
特征的实现。