Rust 字符串连接

10

我本周开始学习Rust编程,但是在理解字符串如何工作方面遇到了很多问题。

目前,我正在尝试编写一个简单的程序,按顺序打印球员名单(仅供学习目的使用)。

let res : String = pl.name.chars().enumerate().fold(String::new(),|res,(i,ch)| -> String {
    res+=format!("{} {}\n",i.to_string(),ch.to_string());
});

println!("{}", res);

这是我的想法,我知道我可以使用for循环,但目标是了解不同的迭代器函数。

所以,我的问题是字符串连接不起作用。

   Compiling prueba2 v0.1.0 (file:///home/pancho111203/projects/prueba2)
src/main.rs:27:13: 27:16 error: binary assignment operation `+=` cannot be applied to types `collections::string::String` and `collections::string::String` [E0368]
src/main.rs:27             res+=format!("{} {}\n",i.to_string(),ch.to_string());
                           ^~~
error: aborting due to previous error
Could not compile `prueba2`.

我尝试使用&str,但无法从ich值创建它们。


这可能不是真正的重复,但根据问题描述看起来是相同的。请随意更新您的标题和问题,以更好地反映为什么它不是重复项,我们可以将其取消标记。 - Shepmaster
1个回答

16
首先,在Rust中,x += y 不可重载,因此 += 操作符只适用于基本数值类型。即使它适用于字符串,它也等同于 x = x + y,就像下面这样:
res = res + format!("{} {}\n",i.to_string(),ch.to_string())

即使类型系统允许这样做(但 Rust 中并不允许,因为未定义 String + String 的“重载”),fold() 也不是这样工作的。你需要这样做:
res + &format!("{} {}\n", i, ch)

或者,作为一个可编译的示例,
fn main(){
    let x = "hello";
    let res : String = x.chars().enumerate().fold(String::new(), |res, (i, ch)| {
        res + &format!("{} {}\n", i, ch)
    });

    println!("{}", res);
}

当你执行fold操作时,不要重新分配累加器变量,你需要返回新值以便在下一次迭代中使用,这正是res + format!(...)所做的。
请注意,我已经删除了to_string()的调用,因为它们是完全不必要的 - 实际上,x.to_string()等同于format!("{}", x),所以你只是在这里执行不必要的分配。
此外,我通过引用获取了format!()的结果:&format!(...)。这是必要的,因为字符串的+“重载”是为String + &str类型对定义的,所以你需要将String(即format!()的结果)转换为&str,这可以通过在此处使用&来简单地完成(由于解引用强制转换)。
实际上,以下方式更有效率:
use std::fmt::Write;

fn main(){
    let x = "hello";
    let res: String = x.chars().enumerate().fold(String::new(), |mut res, (i, ch)| {
        write!(&mut res, "{} {}\n", i, ch).unwrap();
        res
    });

    println!("{}", res);
}

这可以更习惯性地写成

use std::fmt::Write;

fn main(){
    let x = "hello";

    let mut res = String::new(); 
    for (i, ch) in x.chars().enumerate() {
        write!(&mut res, "{} {}\n", i, ch).unwrap();
    }

    println!("{}", res);
}

(在playpen上试一下)

这样就不会创建额外的分配(即从format!()创建新字符串)。 我们只是用新数据填充字符串,非常类似于例如Java中的StringBuilder的工作方式。 这里需要使用use std :: fmt :: Write来允许在&mut String上调用write!()

我还建议阅读官方Rust书中关于字符串的章节(如果您是Rust的新手,则应该阅读整本书)。 它解释了String&str的区别以及如何有效地使用它们。


1
"x += y 在运算符重载方面等同于 x = x + y" → 我认为 += 目前还无法进行重载。 - Veedrac
我认为Veedrac是正确的。 - aochagavia
我改正了,谢谢。 - Vladimir Matveev
2
自从最初提出这个问题以来,已经添加了重载 +=。 - avl_sweden

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