Rust 如何在适当的位置移动str
我想把一根绳子拖到生锈的地方,但我似乎错过了什么。修复可能是微不足道的Rust 如何在适当的位置移动str,rust,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] = b
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();
^~~~~
:8:36:8:41错误:无法将`&`-pointer`*bytes`的不可变解引用借用为可变的
:8让mut slice:&mut[u8]=字节。as_mut_slice();
^~~~~
我读过关于String::as_mut_vec()的书,但它不安全,所以我宁愿不使用它。我也是一个生锈的初学者,但是关于:
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!")
}
}
还要记住,在处理字节序列时,默认的字符串编码是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-nightly(ad9e75938 2015-01-05 00:26:28+0000)没有很好的方法可以做到这一点,部分原因是字符串的UTF-8编码的性质,部分原因是Unicode和文本的固有属性 UTF-8字符串中至少有三层内容可以混洗:
- 原始字节
- 编码码点
- 字位
char
在Rust中)有点道理,但仍然存在“特殊序列”的概念,所谓的序列可以分层到单个字母上,添加变音符号等(例如,像ä
这样的字母可以写成a
加上U+0308,代码点表示)。因此,洗牌字符不会给出无效的UTF-8字符串,但它可能会分解这些码点序列并给出无意义的输出
这让我想到了字形:组成单个可见字符的代码点序列(如ä
在作为一个或两个代码点写入时仍然是单个字形)。这将给出最可靠、最明智的答案
然后,一旦决定要洗牌哪个,就可以制定洗牌策略:
- 如果字符串保证为纯ASCII,则使用
洗牌字节是合理的(根据ASCII假设,这与其他字节相同).shuffle
- 否则,就没有标准的操作方法,可以将元素作为迭代器(
用于代码点或.chars()
用于graphemes),将它们放入带有.graphemes(true)
,洗牌向量,然后使用例如的向量中。collect::()
.iter().map(|x |*x)将所有内容收集回一个新的
字符串中
Vec
不到位是不幸的,但条件很难
(如果您的字符串保证为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
(,它演示了将多个组合字符放在一个字母上。)将上述建议放在一起:
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("Здравствулте мир"));
}
使用std::rand:{Rng,thread\u Rng};
fn str_shuffled(s:&str)->String{
让mut graphemes=s.graphemes(true);
设mut gslice=graphemes.as_mut_slice();
设mut rng=thread_rng();
随机播放(gslice);
gslice.iter().map(| x |*x).collect::()
}
fn main(){
println!(“{}”,stru洗牌(“你好,世界!”);
println!(“{}”,stru洗牌(“selamdünya”);
println!({}),str_洗牌(“你好世界"));
println!(“{}”,strάu shuffled(“γεάσογκόσμο”);
println!(“{}”,str_洗牌(“{}”);
}
这将洗牌一个字符串的字节,但会随机出错,因为Rust字符串被强制为UTF-8,并且不是每个字节的随机洗牌都是UTF-8。@reem,你说得对。我接受了dbaupp的评论,因为这是一个很好的解释。这非常有效。唯一的细节是,因为你sted答案rand已经重新组织了他们的代码。shuffle现在是SliceRandom特性的一部分,因此您可以使用:use rand::seq::SliceRandom;和to shuffle:gslice.shuffle(&mut rng);