兄弟们,正反馈越来越差了。。第一章还能有互动的,第二章就开始没有了。怪不到坚持写下去的人那么少。。希望看过的小伙伴能留下足迹~疑问也好吐槽也罢,或者给咱提提建议。
另外扯个闲篇,上次不是说自行车嘛,然后我买了辆自行车,骑了几次,心率上的太快了。。。随便骑骑心率直奔150+。。。前两天骑了20几分钟心率太高就坐着休息了下,结果降到一百零几的时候突然感觉难受,然后心慌难受,心率在没运动的时候直接上到150+,当时感觉人都要没了,浑身发冷、没力气、心慌,第一次感觉离猝死那么近。。。后来打了个车去医院的路上缓下来了就没去。。但是在家平躺都还是120,110,一直到睡到早上才缓过来。。准备挂个心内专家号看看了。兄弟们,真的身体要紧,天天待电脑跟前人要废了。公司是老板的,身体才是自己的。
好了,书接上回,第三章讲到rust最核心也是最基础的概念 - 《所有权》,最后讲到引用这一块,可以通过引用,去在不持有所有权的情况下传递和修改变量等。除了引用,Rust还有另外一种不持有所有权的数据类型 - 切片。
切片
切片允许我们引用集合中某一段连续的元素序列,而不是整个集合。
假设我们要获取某个字符串的首个单词作为结果返回,这个函数要怎么写?
e.g.
rust
fn first_word(s: &String) -> usize {
let bytes = s.as_bytes(); // 将s转换为字节数组
// 迭代器
for (i, &item) in bytes.iter().emumerate() {
// 判断代表空格的字节
if item == b' ' {
return i;
}
}
s.len()
}
上面这个函数中有目前我们没学到的迭代器等,不过代码咱肯定看得懂意思,就是先转成字节数组,然后遍历,找到字节为空格的就返回当前位置。
这个函数就是实现了期望功能的函数,它能成功的搜索并返回字符串中第一个单词结尾处的位置索引,如果没有空格就返回字符串长度。但是他有一个问题,他将一个usize独立返回出来,这个usize在脱离s之后就毫无意义。
e.g.
rust
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s); // 返回5
s.clear(); // 清空当前字符串
}
上面我们调用first_word获取了&s的第一个单词的位置索引,返回5,然后在下一行清空了字符串,由于5这个位置虽然在我们思维上是与s关联的,但是其实并没有真正的有关联,所以这个word其实就失去了任何意义。 所以我们得找一个方案让他们真正有关联。
字符串切片
字符串切片是指向String对象中某个连续部分的引用。
rust
let s = String::from("hello world");
let hello = &s[0..5]; // hello
let world = &s[6..11]; // world
let all = &s[..]; // hello world
上面的语法就表示一段连续内存的一个视图,起始位置和结束位置用[]表示(左闭右开),这里额外再讲一点,上面s,hello,world,all这几个都是指向某一个内存地址,其中s, hello, all指向的都是同一块内存地址,而world不是,他指向的是w字节对应的内存地址。
如此,我们就可以重新改造下first_word函数:
rust
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b'' {
return &s[..i];
}
}
return [..]
}
字符串字面量就是切片
我们之前使用过的字符串的字面量其实就是一个字符串切片,他是&str类型,指向二进制程序中一个特定位置的切片。
e.g.
rust
let s: &str = "hello world";
let s1: &'static str = "hello world";
let s2: String = s1.to_string();
let s3: &String = &s2;
let s4: &str = &s2[..];
有个小细节要提醒下,&'static str这是静态数据区中的字符串的表示方法,表示s1是一个静态数据区中的字符串的切片。字符串字面量默认会存放在静态数据区里,而静态数据区中的字符串总是贯穿程序运行的整个生命期,直到程序结束的时候才会被释放。上面的例子中,s,s1指向静态数据区,s2指向堆内存,s3是s2的引用,指向的也是堆内存,s4是s2的切片引用,指向的也是同一个堆内存地址。
字符串类型String和&str是可以转换的
e.g.
rust
let s: String = String::from("hello world");
let s1: &str = s.as_str();
let s2: String = s1.to_string();
其他类型的切片
其实我们first_word中的let bytes = s.as_bytes()
这段代码,bytes就是&[u8]
类型的切片,表示一个字节串的切片。
rust
let a:[i32; 5] = [1,2,3,4,5];
let slice = &a[1..3];
上面这个例子的切片类型就是&[i32]
,它内部存储了一个指向起始元素的引用及长度。还有其他各种各样的集合会使用切片类型,用泛型的表示法就表示为&[T]
,T表示任意数组或向量的集合。
OK,本章结束,所有权相关的也就结束了。期望兄弟们动动小手,给点反馈毕竟这种文章本来面向的读者范围就很小了,不像那些面经啥的,随便写写一堆人点赞、评论啥的我还是想跟小伙伴们互动互动,一个人学也很无聊的。。。