1、切片
Rust的另外一种不持有所有权的数据类型:切片(slice)
我们先来做一道题:
编写一个函数,它接收字符串作为参数
返回它在这个字符串里找到的第一个单词
如果函数没找到任何空格,那么整个字符串就被返回
fn main() {
let mut s = String::from("Hello World");
let worldIndex = first_word(&s);
println!("{}",worldIndex)
}
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()
}
上面的代码中,我们完成了这个问题的解,但是这个程序并不完善,因为上面返回的索引后它和当前的字符串就已经没有关系了(脱离了上下文),也就是说,我可以他字符串给清空,但是返回的索引并不会改变了
针对这一问题,rust中也提出了解决的方案,它就是字符串切片
字符串切片是指向字符串中一部分内容的引用
fn main() {
let mut s = String::from("Hello World");
// 0到第5个字节(不包含5)
let s1 = &s[0..5];
// 0到第5个字节(不包含5)
let s2 = &s[..5];
// 0到第最后一个字节
let s3 = &s[..];
}
形式:[开始索引..结束索引]
开始索引就是切片起始位置的索引值
结束索引是切片终止位置的下一个索引值
fn main() {
let mut s = String::from("Hello World");
let hello = &s[0..5];
let world = &s[6..11];
println!("{},{}",hello,world)
}
注意
字符串切片的范围索引必须发生在有效的UTF-8字符边界内。
如果尝试从一个多字节的字符中创建字符串切片,程序会报错并退出
如:
fn main() {
let mut s = String::from("我爱海鲸");
let hello = &s[0..5];
let world = &s[6..11];
println!("{},{}",hello,world)
}
中文是占3个字节的,这里刚好切到了它的中间,所以就报错了
下面我们来重写上面那个寻找字符串的例子
fn main() {
let mut s = String::from("Hello World");
let worldIndex = first_word(&s);
// s.clear();
println!("{}",worldIndex)
}
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[..]
}
符串的例子 然后我们发现没法在清空s的值了,那是因为s发生了不可变的借用,要清空s的值需要发生可变的借用,在rust中如果已经发生了不可变的借用,就无法在进行可变的借用
但是可以先发生可变的借用,在发生不可变的借用。就比如我们可以把s.clear()写在first_word函数调用的前面。
字符串字面值是切片
字符串字面值被直接存储在二进制程序中。
let s = "Hello,World!";
变量s 的类型是&str,它是一个指向二进制程序特定位置的切片
&str是不可变引用,所以字符串字面值也是不可变的
将字符串切片作为参数传递
fn first_word(s: &String) -> &str {
有经验的Rust开发者会采用&str作为参数类型,因为这样就可以同时接收 String和 &str类型的参数了:
fn first_word(s: &str) -> &str {
使用字符串切片,直接调用该函数
使用String,可以创建一个完整的String 切片来调用该函数
定义函数时使用字符串切片来代替字符串引用会使我们的APl更加通用,且不会损失任何功能。
fn main() {
let mut s = String::from("Hello World");
let worldIndex = first_word(&s);
println!("{}",worldIndex);
let mut s = "Hello World";
let worldIndex = first_word(&s);
println!("{}",worldIndex);
}
fn first_word(s:&str)->&str {
let bytes = s.as_bytes();
for (i,&item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i]
}
}
&s[..]
}
其类型的切片
fn main() {
let a = [1,2,3,4,5];
let slice = &a[1..3];
}