这不是确切的用例,但它基本上就是我要做的事情:
let mut username = "John_Smith";
println!("original username: {}",username);
username.set_char_at(4,'.'); // <------------- The part I don't know how to do
println!("new username: {}",username);
我无法在恒定的时间内弄清楚如何做到这一点并且不使用额外的空间。我知道我可以使用&#34;替换&#34;但是替换是O(n)。我可以制作一个角色的矢量,但这需要额外的空间。
我认为您可以创建另一个使用 as_mut_slice 之类的指针变量,但这被认为是不安全的。有一种安全的方法可以在恒定的时间和空间中替换字符串中的字符吗?
答案 0 :(得分:6)
一般情况下?对于任何一对角色?这是不可能的。
string 不是数组。在某些有限的上下文中,可以实现为数组。
Rust支持Unicode,这带来了一些挑战:
为了表示这一点,Rust字符串(现在)是一个UTF-8字节序列:
i
的位置在索引i
和字符串结尾之间,它需要从头开始读取字符串以确切知道它在哪里,即O(N)一般情况下?这是不可能的。
在一个特定且非常特殊的情况下, byte 索引是已知的并且字节编码已知长度一致,可以通过直接修改字节序列返回as_mut_bytes
来实现由于您可能无意中损坏了字符串(请记住,此字节序列必须是UTF-8序列),因此正确标记为unsafe
。
答案 1 :(得分:4)
从Rust 1.27开始,您现在可以使用String::replace_range
:
let mut username = String::from("John_Smith");
println!("original username: {}", username); // John_Smith
username.replace_range(4..5, ".");
println!("new username: {}", username); // John.Smith
replace_range
无法与&mut str
一起使用。如果范围的大小和替换字符串的大小不同,则必须能够调整基础String
的大小,因此需要&mut String
。但是在你询问(用另一个单字节字符替换单字节字符)的情况下,它的内存使用和时间复杂度都是O(1)。
Vec
,Vec::splice
上有类似的方法。它们之间的主要区别在于splice
返回一个生成已删除项的迭代器。
答案 2 :(得分:2)
如果您只想处理ASCII,则有单独的类型:
use std::ascii::{AsciiCast, OwnedAsciiCast};
fn main() {
let mut ascii = "ascii string".to_string().into_ascii();
*ascii.get_mut(6) = 'S'.to_ascii();
println!("result = {}", ascii);
}
有一些缺失的部分(例如into_ascii
的{{1}}),但它会做你想要的。
如果输入字符串无效&str
,则to_/into_ascii
的当前实现会失败。有ascii
(可能失败的方法的旧命名),但将来可能会重命名为to_ascii_opt
(并删除或重命名失败的方法)。