2.6 Rust Slice Type

字符串操作

fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}

Because we need to go through the String element by element and check whether a value is a space, we’ll convert our String to an array of bytes using the as_bytes method

 For now, know that iter is a method that returns each element in a collection and that enumerate wraps the result of iter and returns each element as part of a tuple instead. The first element of the tuple returned from enumerate is the index, and the second element is a reference to the element. This is a bit more convenient than calculating the index ourselves.

Because the enumerate method returns a tuple, we can use patterns to destructure that tuple, just like everywhere else in Rust. So in the for loop, we specify a pattern that has i for the index in the tuple and &item for the single byte in the tuple. Because we get a reference to the element from .iter().enumerate(), we use & in the pattern.

Inside the for loop, we search for the byte that represents the space by using the byte literal syntax. If we find a space, we return the position. Otherwise, we return the length of the string by using s.len()

fn main() {
    let mut s = String::from("hello world");

    let _word = first_word(&s); // word will get the value 5

    println!("{},{}",s,_word);
    s.clear(); // this empties the String, making it equal to ""

    // word still has the value 5 here, but there's no more string that
    // we could meaningfully use the value 5 with. word is now totally invalid!
}


fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}

 

字符串切片

str[index..end_position]

index:字符索引位置,从0开始

end_position:字符位置,从1开始

let s = String::from("hello world");

let hello = &s[0..5];
let world = &s[6..11];

 

With Rust’s .. range syntax, if you want to start at the first index (zero), you can drop the value before the two periods. In other words, these are equal:

let s = String::from("hello");

let slice = &s[0..2];
let slice = &s[..2];

By the same token, if your slice includes the last byte of the String, you can drop the trailing number. That means these are equal:

let s = String::from("hello");

let len = s.len();

let slice = &s[3..len];
let slice = &s[3..];

You can also drop both values to take a slice of the entire string. So these are equal:

let s = String::from("hello");

let len = s.len();

let slice = &s[0..len];
let slice = &s[..];

Note: String slice range indices must occur at valid UTF-8 character boundaries. If you attempt to create a string slice in the middle of a multibyte character, your program will exit with an error.

 切片字符串操作

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

第一种方式为直接对字符串本身进行操作,没有第二个变量产生,切片则是新定义了一个变量,指向了原字符串的部分内容。当作用域发生变化时,它们的不同就会显现出来。

 下面这一段代码是正确的

fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s);

    s.clear(); // error!

    println!("the first word is: {}", word);
}

fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}

 

下面的代码是错误的

 

下面test_s2方法是错误的,原因在于first_word2方法返回的是可变字符串s的一个切片,切片是什么?

切片只是原始字符串的一个局部引用,没有ownership,本身也不存储数据,只有一个指针和要读取字符长度

在这个方法,s.clear()方法清空了原始字符串,然后又使用了word,此时rust就认为这种做法破坏了切片word的原本的内容,将这种做法定义为error

 

pub fn test_s2(){
    let mut s = String::from("hello world");

    let word = first_word2(&s);

    s.clear(); // error!

    println!("the first word is: {}", word);

}



fn first_word2(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[..i];
        }
    }
    &s[..]
}

 

下面的代码是正确的,只需要更换一下对切片使用的位置

pub fn test_s2(){
    let mut s = String::from("hello world");

    let word = first_word2(&s);
    println!("the first word is: {}", word);
    s.clear(); // error!
}


fn first_word2(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[..i];
        }
    }
    &s[..]
}

 

posted @ 2019-04-12 13:03  方诚  阅读(377)  评论(0编辑  收藏  举报