这个非常简单的Rust程序:
fn main() {
let c = "hello";
println!(c);
}
抛出以下编译时错误:
error: expected a literal
--> src/main.rs:3:14
|
3 | println!(c);
| ^
在Rust的早期版本中,错误说:
error: format argument must be a string literal.
println!(c);
^
用以下代码替换程序:
fn main() {
println!("Hello");
}
工作正常。
这个错误的含义对我来说并不清楚,谷歌的搜索并没有真正揭示它。为什么将c
传递给println!
宏会导致编译时错误?这似乎很不寻常。
答案 0 :(得分:50)
这应该有效:
fn main() {
let c = "hello";
println!("{}", c);
}
字符串"{}"
是一个模板,其中{}
将被传递给println!
的下一个参数替换。
答案 1 :(得分:39)
TL; DR如果您不关心为什么并且只想修复它,请参阅the sibling answer。
原因
fn main() {
let c = "hello";
println!(c);
}
无法工作是因为println!
宏在编译时查看字符串 并验证参数和参数说明符的数量和类型是否匹配(这是一件非常好的事情!) 。此时,在宏观评估期间,无法判断c
来自文字或函数或者您有什么。
以下是宏扩展到的示例:
let c = "hello";
match (&c,) {
(__arg0,) => {
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR: &'static [&'static str] = &[""];
::std::io::stdio::println_args(&::std::fmt::Arguments::new(
__STATIC_FMTSTR,
&[::std::fmt::argument(::std::fmt::Show::fmt, __arg0)]
))
}
};
我不认为编译器实际上不可能可以解决这个问题,但这可能需要做很多工作(可能收益不大)。宏操作AST的部分,我假设只有类型信息。为了在这种情况下工作,AST必须包括标识符的来源和足够的信息来确定它的安全"。此外,它可能与类型推断相互影响很差 - 您还希望在它被选中之前知道类型!
错误消息要求输入"字符串文字"。关于这意味着什么的SO问题,链接到Wikipedia entry:
文字是在源代码中表示固定值的符号
"foo"
是字符串文字,8
是数字文字。 let s = "foo"
是一个语句,它将字符串文字的值赋给标识符(变量)。 println!(s)
是一个为宏提供标识符的语句。
答案 2 :(得分:3)
如果你的格式字符串只能重复使用次数,而且只会改变一些变量数据,那么一个小函数可能比宏更好:
fn pr(x: &str) {
println!("Some stuff that will always repeat, something variable: {}", x);
}
pr("I am the variable data");
输出
一些总会重复的东西,变量:我是变量数据
答案 3 :(得分:2)
如果你真的想定义println的第一个参数!在一个地方,我找到了一种方法。您可以使用宏:
macro_rules! hello {() => ("hello")};
println!(hello!());
这里看起来不太有用,但我想在一些地方使用相同的格式,在这种情况下,该方法非常有用:
macro_rules! cell_format {() => ("{:<10}")}; // Pads with spaces on right
// to fill up 10 characters
println!(cell_format!(), "Foo");
println!(cell_format!(), 456);
宏使我免于在代码中复制格式化选项。
显然,你也可以使宏更加花哨,并在必要时使用参数来打印具有不同参数的不同内容。