我想在Rust中使用一个字符串,但我似乎错过了一些东西。修复可能是微不足道的......
use std::rand::{Rng, thread_rng};
fn main() {
// I want to shuffle this string...
let mut value: String = "SomeValue".to_string();
let mut bytes = value.as_bytes();
let mut slice: &mut [u8] = bytes.as_mut_slice();
thread_rng().shuffle(slice);
println!("{}", value);
}
我得到的错误是
<anon>:8:36: 8:41 error: cannot borrow immutable dereference of `&`-pointer `*bytes` as mutable
<anon>:8 let mut slice: &mut [u8] = bytes.as_mut_slice();
^~~~~
我读到了String :: as_mut_vec(),但它不安全,所以我不想使用它。
答案 0 :(得分:12)
没有很好的方法可以做到这一点,部分原因在于字符串的UTF-8编码的性质,部分原因是由于Unicode和文本的固有属性。
至少有三层可以在UTF-8字符串中混洗的东西:
混乱原始字节可能会将无效的UTF-8字符串作为输出,除非该字符串完全是ASCII。非ASCII字符被编码为多个字节的特殊序列,并且随机抽取它们几乎肯定不会在最后以正确的顺序获得它们。因此,改组字节通常不好。
改变代码点(Rust中的char
)会更有意义,但仍然存在&#34;特殊序列&#34;的概念,其中所谓的combining characters可以分层添加变音符号等单个字母(例如ä
之类的字母可以写为a
加上U + 0308,代码点代表the diaeresis)。因此,改组字符不会产生无效的UTF-8字符串,但它可能会破坏这些代码点序列并给出无意义的输出。
这让我看到字形:构成单个可见字符的代码点序列(如ä
在写为一个或两个代码点时仍然是一个字形)。这将给出最可靠明智的答案。
然后,一旦你决定要改组你的洗牌策略:
.shuffle
对字节进行混洗是明智的(使用ASCII假设,这相当于其他字符串).chars()
代码点或.graphemes(true)
代表字形),将它们放入向量中使用.collect::<Vec<_>>()
,对矢量进行随机播放,然后将所有内容收集回到新的String
中,例如.iter().map(|x| *x).collect::<String>()
。处理代码点和字形的难度是因为UTF-8不会将它们编码为固定宽度,因此无法将随机代码点/字形输出并将其插入其他地方,或以其他方式交换两个元素高效......不仅仅将所有内容解码为外部Vec
。
不合适是不幸的,但字符串很难。
(如果你的字符串保证是ASCII,那么使用像ascii
提供的类似Ascii
的类型将是保持类型级别的正确的好方法。)
作为三件事差异的一个例子,请看一下:
fn main() {
let s = "U͍̤͕̜̲̼̜n̹͉̭͜ͅi̷̪c̠͍̖̻o̸̯̖de̮̻͍̤";
println!("bytes: {}", s.bytes().count());
println!("chars: {}", s.chars().count());
println!("graphemes: {}", s.graphemes(true).count());
}
打印:
bytes: 57
chars: 32
graphemes: 7
(Generate your own,它演示了将多个组合字符放在一个字母上。)
答案 1 :(得分:2)
汇总上述建议:
use std::rand::{Rng, thread_rng};
fn str_shuffled(s: &str) -> String {
let mut graphemes = s.graphemes(true).collect::<Vec<&str>>();
let mut gslice = graphemes.as_mut_slice();
let mut rng = thread_rng();
rng.shuffle(gslice);
gslice.iter().map(|x| *x).collect::<String>()
}
fn main() {
println!("{}", str_shuffled("Hello, World!"));
println!("{}", str_shuffled("selam dünya"));
println!("{}", str_shuffled("你好世界"));
println!("{}", str_shuffled("γειά σου κόσμος"));
println!("{}", str_shuffled("Здравствулте мир"));
}
答案 2 :(得分:0)
我也是Rust的初学者,但是呢:
fn main() {
// I want to shuffle this string...
let value = "SomeValue".to_string();
let mut bytes = value.into_bytes();
bytes[0] = bytes[1]; // Shuffle takes place.. sorry but std::rand::thread_rng is not available in the Rust installed on my current machine.
match String::from_utf8(bytes) { // Should not copy the contents according to documentation.
Ok(s) => println!("{}", s),
_ => println!("Error occurred!")
}
}
另外请记住,当摆弄字节序列时,Rust默认字符串编码是UTF-8。 ;)
这是一个很好的建议,请引导我以下解决方案,谢谢!
use std::rand::{Rng, thread_rng};
fn main() {
// I want to shuffle this string...
let value: String = "SomeValue".to_string();
let mut bytes = value.into_bytes();
thread_rng().shuffle(&mut *bytes.as_mut_slice());
match String::from_utf8(bytes) { // Should not copy the contents according to documentation.
Ok(s) => println!("{}", s),
_ => println!("Error occurred!")
}
}
rustc 0.13.0-夜间(ad9e75938 2015-01-05 00:26:28 +0000)