为什么无法使用格式化打印打印结构体字段?

6

像下面的代码一样,它可以使用格式化打印来输出基本值或带有派生调试属性的结构体等内容。 但是当值为结构体字段时,无法直接输出。

#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let a = 3;
    let p = Point { x: 5, y: 10 };

    println!("{}", a); // Working
    println!("{a}"); // Working

    println!("{:?}", p); // Working
    println!("{p:?}"); // Working

    println!("{} {}", p.x, p.y); // Working
    println!("{p.x} {p.y}"); // Not working
}

错误信息如下。
error: invalid format string: expected `'}'`, found `'.'`
  --> src/main.rs:18:17
   |
18 |     println!("{p.x} {p.y}"); // Not working
   |               - ^ expected `}` in format string
   |               |
   |               because of this opening brace
   |
   = note: if you intended to print `{`, you can escape it using `{{`

error: could not compile `rust-ex` due to previous error

我认为p.x和p.y的类型是i32,所以可以用格式化打印输出,但实际上不能。有没有一种方法可以用格式化打印输出结构体字段?或者需要实现什么?

2
错误信息很糟糕,有一个Rust问题跟踪 - Chayim Friedman
2个回答

8

你的问题不是格式问题,而是与println!在其格式化字符串中接受的内容有关。

与其他语言中可能遇到的情况相反,在 println! 中花括号内的部分不是字符串转义,这意味着你可以放置任何(可打印的)Rust表达式。相反,你应该将其视为命名参数。因此,它只能是变量名称。如果你没有使用该名称的变量,则println! 还允许你模拟变量定义,像这样:

println!("{px}", px = p.x);

2

另一个类似但不同的问题是当你有一个Rust变量是下划线时,尝试使用println!

let _ = 2;
println!("Value of _ is {_}");

错误为:
invalid format string: invalid argument name `_`
...
println!("Value of _ is {_}");
                         ^ invalid argument name in format string

这可能是因为下划线本来就被忽略了

在Rust中,下划线(_)是一个保留标识符,在不同的上下文中具有不同的用途。通常意味着某些东西被忽略了。

其他网站解释说,在Rust中,下划线“不绑定到变量”;或者“不拥有对象的所有权”

请参考@jthulhu的评论——在Rust中,_不仅是被忽略的,而且_变量不能被使用,因此甚至没有被分配(这解释了我的错误信息)。这与其他编程语言不同,在其他编程语言中,_变量只是一个惯例,表示_变量应该被忽略,但可以被使用。如@jthulhu所说,在Rust中:"基本上,执行let _ = 3;甚至没有任何优化效果"

我知道OP已经找到了最佳答案。我只是想提供这个答案,以防其他人搜索"invalid format string"或"invalid argument name _"并找到这个SO问题。

如果您尝试了解决方法,例如:

 println!("Value of _ is {}", _);

然后你会得到一个新的错误,强化了下划线变量永远不应该被使用的想法:

in expressions, `_` can only be used on the left-hand side of an assignment 
`_` not allowed here

所以下划线变量可以像我上面的代码一样出现在赋值语句的左侧,或者在这个下划线表达式中,其中_表示解构赋值中的占位符但是你不能在后面引用下划线变量,包括在println!中。唯一的解决方案是使用不同的变量名。


1
请注意,与其他一些语言不同,其中“_”是变量不再使用的约定名称,在Rust中,“_”具有特殊含义:它确实意味着它永远不会再次使用,因此不需要分配变量。基本上,执行let _ = 3;即使没有优化也不会产生任何结果。 - jthulhu
感谢 @jthulhu -- 你说得没错,我习惯了“其他语言的约定”,即 _ 不应再次使用(但 可以 再次使用)。但是在 Rust 中,你不能再次使用它!虽然您接受的答案确实是最好的答案,但我认为其他 Rust 新手可能会发现这一点很有用.... - Nate Anderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接