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

现在,我正在try 做一个简单的程序,打印一个球员名单,并附上他们的订单(仅供学习之用).

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

这是我的 idea ,我知道我可以使用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个值创建它们.

推荐答案

首先,在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);
}

执行折叠时,不需要重新分配累加器变量,需要返回新值,以便在下一次迭代中使用,这正是res + format!(...)所要做的.

请注意,我删除了to_string()个调用,因为它们完全不必要——事实上,x.to_string()相当于format!("{}", x),所以这里只执行不必要的分配.

另外,我引用了format!()个结果:&format!(...).这是必要的,因为字符串的+"重载"是为String + &str对类型定义的,所以您需要从String(format!()的结果)转换为&str,这可以通过在这里使用&来实现(因为deref强制).

事实上,以下方法更有效:

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 书中读the chapter on strings本(如果你是Rust 新手,那就把这本书作为一个整体).它解释了String&str是什么,它们有什么不同,以及如何有效地使用它们.

Rust相关问答推荐

trait声明中的生命周期参数

如何最好地并行化修改同一Rust向量的多个切片的代码?

Box::new()会从一个堆栈复制到另一个堆吗?

Rust类似功能是C++命名空间吗?

使用极点数据帧时,找不到枚举结果的方法lazy()

如果包名称与bin名称相同,并且main.ars位于工作区的同一 crate 中,则无法添加对lib.ars的依赖

异步函数返回的future 生存期

为什么Option类型try块需要类型注释?

实现 Deref 的 struct 可以返回对外部数据的引用吗?

使用占位符获取用户输入

将 &str 或 String 保存在变量中

当没有实际结果时,如何在 Rust 中强制执行错误处理?

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

从 HashMap>, _> 中删除的生命周期问题

从 Axum IntoResponse 获取请求标头

Rustlings 切片原语

相交着色器从 SSBO 中读取零

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

HashMap entry() 方法使borrow 的时间比预期的长

如果参数为 Send,则返回 Future Send