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字符串中至少有三层内容可以混洗:

  • 原始字节
  • 编码码点
  • 字位
洗牌原始字节可能会将无效的UTF-8字符串作为输出,除非该字符串完全是ASCII。非ASCII字符被编码为多个字节的特殊序列,而对这些字符进行混洗几乎肯定不会使它们在最后按正确的顺序排列。因此,洗牌字节通常是不好的

洗牌代码点(
char
在Rust中)有点道理,但仍然存在“特殊序列”的概念,所谓的序列可以分层到单个字母上,添加变音符号等(例如,像
ä
这样的字母可以写成
a
加上U+0308,代码点表示)。因此,洗牌字符不会给出无效的UTF-8字符串,但它可能会分解这些码点序列并给出无意义的输出

这让我想到了字形:组成单个可见字符的代码点序列(如
ä
在作为一个或两个代码点写入时仍然是单个字形)。这将给出最可靠、最明智的答案

然后,一旦决定要洗牌哪个,就可以制定洗牌策略:

  • 如果字符串保证为纯ASCII,则使用
    .shuffle
    洗牌字节是合理的(根据ASCII假设,这与其他字节相同)
  • 否则,就没有标准的操作方法,可以将元素作为迭代器(
    .chars()
    用于代码点或
    .graphemes(true)
    用于graphemes),将它们放入带有
    的向量中。collect::()
    ,洗牌向量,然后使用例如
    .iter().map(|x |*x)将所有内容收集回一个新的
    字符串中
处理代码点和图形的困难是因为UTF-8没有将它们编码为固定宽度,因此无法将随机代码点/图形取出并插入其他地方,或者有效地交换两个元素。。。无需将所有内容解码为外部
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);