我试图通过将其传递给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, 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 {
^~~~
为什么我会收到此错误,如何实现我的目标?
答案 0 :(得分:10)
您根本无法更改字符串切片。 &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)
效率,因为它必须遍历原始切片,并且它也无法正确处理复杂字符 - 它可能会替换字母但会留下重音,反之亦然。
更正确的文本处理方式是迭代字形集群,它将正确地采用变音符号和其他类似的东西(主要是):
fn replace_grapheme_at(s: &str, idx: uint, c: &str) -> String {
let mut r = String::with_capacity(s.len());
for (i, g) in s.grapheme_indices(true) {
r.push_str(if i == idx { c } else { g });
}
r
}
std::ascii
模块中对纯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字符,则会发生混乱。