Rust是否支持类似Ruby的字符串插值?

81

在 Ruby 中我可以这样做。

aaa = "AAA"
bbb = "BBB #{aaa}"

puts(bbb)

> "BBB AAA"

这种语法的目的是消除重复,并使其感觉像一个shell脚本-非常适合于大量字符串操作。

Rust支持此功能吗?或者有计划支持此功能吗?或者有一些可以模仿此功能的特性吗?


1
这个问题有一个Rust RFC。请随意点赞。 - ostrokach
2
看起来RFC现在几乎已经稳定了。https://github.com/rust-lang/rust/pull/90473 - BallpointBen
3个回答

86

这是自 Rust 1.58 起可用!以下是语法:

let (person, species, name) = ("Charlie Brown", "dog", "Snoopy");

// implicit named argument `person`
print!("Hello {person}");

// implicit named arguments `species` and `name`
format!("The {species}'s name is {name}.");

RFC 2795 是原始提案。


6
IMO来源于JS,RFC是什么我不清楚。提到的完全内插语法{( )}阅读起来很糟糕,特别是与${ }相比,而且作者神秘地对支持任意表达式的内插有很强的偏见。相反,他们宁愿处理字符串连接方式对宏格式系统造成的影响。使用一个字符串文字语法,在${ }中嵌入任意表达式就简单多了。 - Andy
22
它是在Rust 1.58.0版本中发布的。 - Rodrigo Stuchi
1
@Andy,你没有理解Rust的类型系统、安全性和编译时宏的重点。请参考这个SO答案了解详情。 - Paul-Sebastian Manole
3
我不认为在字符串模板字面量中嵌入任意表达式进行类型检查是不可能的。似乎主要问题是他们想继续使用宏来对普通字符串模板进行格式化,而不是将新的字符串模板字面量语法添加到语言语法中。 - Andy
@Andy 事情是,类型检查很难,生命周期检查也很难。而且当它太难时,你无法告诉编译器“相信我,这个的类型是这样的”,就像在TypeScript中一样,快乐地混淆转换和注释,因为它们都无关紧要。相反,对于大多数类型和所有生命周期的情况,你温柔地告诉它:“我们能让这个变量成为这个类型吗?”如果可以,你就拥有了类型安全性。因此,强制使用变量可以防止由于表达式例如一个&str而出现需要进行模糊重构的风险 - 4xel
@Andy 但我认为他们对此持谨慎态度的主要原因,除了为了让人类和编译器的作用域和类型分析保持简单外,还有设计空间的考虑。表达式已经可以包含引号、大括号甚至冒号。我想不出会发生冲突的情况,但是'lbl : {这样的语法结构却非常接近(这是一个标签冒号,还是一个格式化冒号?)。现在仍然有很多可能性,但是当涉及到承诺新功能和语法时,Rust开发者非常谨慎。他们可能从JavaScript的例子中吸取了教训,后者不加思索地添加每一个新潮流,并陷入了遗留代码的困境。 - 4xel

80

Rust有字符串格式化功能。

fn main() {
    let a = "AAA";
    let b = format!("BBB {}", a);
    println(b);
}
// output: BBB AAA
在Rust版本中,没有额外的重复,但必须显式调用format!(),并且插入的值与字符串分开。这基本上与Python和C#开发人员习惯的做法相同,其原理是这种技术使得将代码本地化到其他语言变得更容易。
Rust邮件列表中有一次存档讨论([rust-dev] Suggestions),其中讨论了不同类型的字符串内插。

17
讨论似乎没有继续下去,很遗憾。 - eonil
@ChrisMorgan:那只是背景信息。 过去23个月中,背景信息并没有改变,除非你有什么想分享的。 - Dietrich Epp
10
您还可以使用format!("BBB {name}", name = a)。 (实际上,可能可以使用与format相同的解析和宏基础设施来实现inline_fmt!("BBB {a}"),但是卫生可能需要一些技巧来解决。) - huon
10
Python和C#都已经添加了字符串插值功能。Python的写法是:f'{a} times {b} is {a * b}.',而C#的写法是:$"{a} times {b} is {a * b}" - Ghost4Man
3
这是关于该主题的最新讨论:https://github.com/rust-lang/rfcs/issues/1250。目前这个答案已经不太相关了,因为它认为 Rust 的字符串格式化是为了便于移植到其他语言,而这已经不再正确 - Python、C#、JS 等语言的语法更接近 Ruby 而非 Rust。 - Thibaud Colas
显示剩余3条评论

46

从 Rust 1.58 开始,你可以利用格式字符串中的捕获标识符。这使得你可以做出如下操作:

let msg = "here";
let s = format!("Abc {msg}");  
println!("Hi t{msg}");   // prints "Hi there"
println!("{s}");         // prints "Abc here" 

这个功能可以被看作是字符串插值的子集。像format!("Abc {a+b}")这样的表达式不受支持,目前也不清楚是否会添加此类功能。同时也有讨论要添加一些点路径的子集表达式,例如format!("Abc {foo.bar}")

另外需要注意的是,Rust 2021版腾出空间为将来语言的增加留下了余地,例如f"hello {name}",这将允许更简洁的字符串插值,与大多数现代语言相当。


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