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

推荐答案

TL;DR如果你不在乎why,只想修复它,请参见the sibling answer.


原因是

fn main() {
    let c = "hello";
    println!(c);
}

无法工作是因为println!宏查看字符串at compile time,并验证参数和参数说明符在数量和类型上是否匹配(这是一件非常好的事情!).此时,在宏计算过程中,无法判断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)]
        ))
    }
};

我不认为编译器实际上需要impossible才能弄明白这一点,但这可能需要大量工作,但可能收获甚微.宏操作AST的部分,AST只有类型信息.要在这种情况下工作,AST必须包含标识符的来源和足够的信息,以确定是否可以将其用作格式字符串.此外,它可能与类型推断交互不好——你可能想在 Select 类型之前就知道它!

错误消息要求输入"字符串文字".What does the word "literal" mean?询问这意味着什么,链接到Wikipedia entry:

文字是一种表示源代码中固定值的符号

"foo"是字符串文字,8是数字文字.let s = "foo"是一条语句,它将字符串文字的值分配给标识符(变量).println!(s)是为宏提供标识符的语句.

Rust相关问答推荐

Rust ndarray:如何从索引中 Select 数组的行

获取已知数量的输入

如何轮询 Pin>?

通过异常从同步代码中产生yield 是如何工作的?

Rust 中的静态引用

如何限制 GtkColumnView 行数

Rust:为什么 Pin 必须持有指针?

从Rust 的临时文件中创建引用是什么意思?

Rust 中的自动取消引用是如何工作的?

使用方法、关联函数和自由函数在 Rust 中初始化函数指针之间的区别

在 RefCell 上borrow

Rust,我如何正确释放堆分配的内存?

如何在 C++ 和 Rust 之间共享 pthread 同步原语?

将文件的第一行分别读取到文件的其余部分的最有效方法是什么?

Cargo:如何将整个目录或文件包含在功能标志中?

Rust:如果我知道只有一个实例,那么将可变borrow 转换为指针并返回(以安抚borrow 判断器)是否安全?

如何重写这个通用参数?

为什么这里需要类型注解?

为什么在使用 self 时会消耗 struct 而在解构时不会?

为什么 Bevy 的 Trait 边界不满足 Rapier 物理插件?