如何在Rust的字符串开头"剪切"字符?

Lon*_*xel 2 string rust

我想要一个可以接受两个参数(string, number of letters to crop off front)并返回相同字符串的函数,除了字符x之前的字母.

如果我写

let mut example = "stringofletters";
CropLetters(example, 3);
println!("{}", example);
Run Code Online (Sandbox Code Playgroud)

然后输出应该是:

ingofletters
Run Code Online (Sandbox Code Playgroud)

有什么方法可以做到这一点吗?

She*_*ter 7

您原始代码的问题:

  1. 功能使用snake_case,类型和特征使用CamelCase.
  2. "foo"是类型的字符串文字&str.这些可能不会改变.您将需要已分配堆的内容,例如a String.
  3. 通话crop_letters(stringofletters, 3)所有权转让stringofletters这种方法,这意味着你将无法再使用该变量.你必须传入一个可变引用(&mut).
  4. Rust字符串不是ASCII,它们是UTF-8.您需要确定每个字符需要多少字节.char_indices这是一个很好的工具.
  5. 您需要处理字符串短于3个字符的情况.
  6. 一旦你有了字符串新开头的字节位置,就可以用来从字符串drain中移出一大块字节.我们只删除这些字节,然后String移动剩余的字节.
fn crop_letters(s: &mut String, pos: usize) {
    match s.char_indices().nth(pos) {
        Some((pos, _)) => {
            s.drain(..pos);
        }
        None => {
            s.clear();
        }
    }
}

fn main() {
    let mut example = String::from("stringofletters");
    crop_letters(&mut example, 3);
    assert_eq!("ingofletters", example);
}
Run Code Online (Sandbox Code Playgroud)

如果您实际上不需要修改原件,请参阅Chris Emerson的答案String.


Chr*_*son 7

在许多用途中,简单地返回输入切片是有意义的,避免任何复制.转换@ Shepmaster的解决方案以使用不可变切片:

fn crop_letters(s: &str, pos: usize) -> &str {
    match s.char_indices().skip(pos).next() {
        Some((pos, _)) => &s[pos..],
        None => "",
    }
}

fn main() {
    let example = "stringofletters"; // works with a String if you take a reference
    let cropped = crop_letters(example, 3);
    println!("{}", cropped);
}
Run Code Online (Sandbox Code Playgroud)

变异版本的优点是:

  • 无需复印件.cropped.to_string()如果您想要新分配的结果,可以打电话; 但你不必.
  • 它适用于静态字符串切片以及可变String等.

缺点是,如果你真的有一个你想要修改的可变字符串,那么你需要分配一个新的字符串效率会稍差String.