Rust 使用函数就地编辑字符串
我试图通过将字符串传递给mutate()来在位编辑字符串,请参见下文 简化示例:Rust 使用函数就地编辑字符串,rust,lifetime,Rust,Lifetime,我试图通过将字符串传递给mutate()来在位编辑字符串,请参见下文 简化示例: fn mutate(string: &mut &str) -> &str { string[0] = 'a'; // mutate string string } fn do_something(string: &str) { println!("{}", string); } fn main() { let string = "Hello,
fn mutate(string: &mut &str) -> &str {
string[0] = 'a'; // mutate string
string
}
fn do_something(string: &str) {
println!("{}", string);
}
fn main() {
let string = "Hello, world!";
loop {
string = mutate(&mut string);
do_something(string);
}
}
但我得到以下编译错误:
main.rs:1:33: 1:37 error: missing lifetime specifier [E0106]
main.rs:1 fn mutate(string: &mut &str) -> &str {
^~~~
main.rs:1:33: 1:37 help: this function's return type contains a borrowed value, but the signature does not say which one of `string`'s 2 elided lifetimes it is borrowed from
main.rs:1 fn mutate(string: &mut &str) -> &str {
^~~~
为什么会出现此错误?如何实现我的目标?您根本无法更改字符串片段
&mut&str
无论如何都不是合适的类型,因为它实际上是指向不可变切片的可变指针。所有的字符串片段都是不可变的
在Rust中,字符串是有效的UTF-8序列,UTF-8是可变宽度编码。因此,通常更改字符可能会更改字符串的长度(以字节为单位)。这不能用切片来完成(因为切片总是有固定的长度),这可能会导致重新分配所拥有的字符串。此外,在99%的情况下,更改字符串中的字符并不是您真正想要的
要使用unicode代码点执行所需操作,您需要执行以下操作:
fn replace_char_at(s: &str, idx: uint, c: char) -> String {
let mut r = String::with_capacity(s.len());
for (i, d) in s.char_indices() {
r.push(if i == idx { c } else { d });
}
r
}
但是,这具有O(n)
效率,因为它必须遍历原始切片,而且对于复杂字符也无法正常工作-它可能会替换字母,但留下重音,反之亦然
更正确的文本处理方法是迭代通过grapheme集群,它将正确地使用变音符号和其他类似的东西(主要是):
模块中也有一些对纯ASCII字符串的支持,但可能很快就会进行改革。无论如何,这就是它的使用方式:
fn replace_ascii_char_at(s: String, idx: uint, c: char) -> String {
let mut ascii_s = s.into_ascii();
ascii_s[idx] = c.to_ascii();
String::from_utf8(ascii_s.into_bytes()).unwrap()
}
如果
s
包含非ASCII字符或c
不是ASCII字符,它会死机。您怎么会认为&str
或String
实现索引输出
?Unicode比这要复杂得多,因此为了避免错误,他们不这样做。我不知道如何实现你想做的事情,但…可能是我的C背景,使我想索引字符串。我知道这是不可能的生锈?我需要使用循环吗?假设我只想编辑字符串中的第100个字符,我需要在前99个字符上循环,然后才能编辑第100个字符?
fn replace_ascii_char_at(s: String, idx: uint, c: char) -> String {
let mut ascii_s = s.into_ascii();
ascii_s[idx] = c.to_ascii();
String::from_utf8(ascii_s.into_bytes()).unwrap()
}