调用println!错误:预期文字/格式参数必须是字符串文字

时间:2015-01-01 21:10:14

标签: rust

这个非常简单的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!宏会导致编译时错误?这似乎很不寻常。

4 个答案:

答案 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);

宏使我免于在代码中复制格式化选项。

显然,你也可以使宏更加花哨,并在必要时使用参数来打印具有不同参数的不同内容。