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[..] }