本系列文章是jon gjengset发布的crust of rust系列视频的学习笔记,crust of rust是一系列持续更新的rust中级教程。
在这篇文章中,我们将研究一个需要显式注释多个生命期的例子。我们还将讨论不同字符串类型之间的一些差异,以及在自定义的trait上引入泛型。这个例子是根据给定的字符串和分隔符对字符串进行拆分。
创建一个新项目:
cargo new --lib strsplit lib.rs中写入如下代码: 1#[derive(debug)] 2pub struct strsplit { 3 remainder: &'a str, 4 delimiter: &'a str, 5} 6 7#[allow(dead_code)] 8impl strsplit { 9 pub fn new(haystack: &'a str, delimiter: &'a str) -> self {10 self {11 remainder: haystack,12 delimiter,13 }14 }15}1617impl iterator for strsplit {18 type item = &'a str;1920 fn next(&mut self) -> option {21 if let some(next_delim) = self.remainder.find(self.delimiter) {22 let until_remainder = &self.remainder[..next_delim];23 self.remainder = &self.remainder[next_delim + self.delimiter.len()..];24 some(until_remainder)25 }else if self.remainder.is_empty() {26 none27 }else {28 let rest = self.remainder;29 // 为什么空字符串可以赋值给self.remainder ?30 self.remainder = ;31 some(rest)32 }33 }34}3536#[test]37fn it_works() {38 let haystack = a b c d e;39 let letters: vec = strsplit::new(haystack, ).collect();40 assert_eq!(letters, vec![a, b, c, d, e]);41}
strsplit 与成员 remainder,delimiter 拥有相同的生命周期
使用fn new()方法构建的strsplit与传入的参数haystack,delimiter 拥有相同的生命周期
在实现iterator trait时,迭代的结果也要与strsplit拥有相同的生命周期,是因为要在strsplit的成员remainder上做迭代。
在第30行,为什么空字符串可以赋值给self.remainder?这是因为self.remainder的生命周期是&'a str,空字符串的生命周期是&'static str,static的生命周期一直到程序结束。 修复bug 这里有一个bug,添加如下测试方法:
1#[test]2fn tail() {3 let haystack = a b c d ;4 let letters: vec = strsplit::new(haystack, ).collect();5 assert_eq!(letters, vec![a, b, c, d, ]);6} 执行cargo test:running 2 teststest str_split_1::it_works ... oktest str_split_1::tail ... failed 我们将struct strsplit的成员remainder定义为option类型来修复这个bug: 1/** 2 * strsplit 与成员 remainder,delimiter 拥有相同的生命周期 3 */ 4#[derive(debug)] 5pub struct strsplit { 6 // 使用option 7 remainder: option, 8 delimiter: &'a str, 9}1011#[allow(dead_code)]12impl strsplit {13 /**14 * 新构建的strsplit与传入的参数haystack,delimiter 拥有相同的生命周期15 */16 pub fn new(haystack: &'a str, delimiter: &'a str) -> self {17 self {18 remainder: some(haystack),19 delimiter,20 }21 }22}2324impl iterator for strsplit {25 // 迭代的结果也要与strsplit拥有相同的生命周期,是因为要在strsplit的成员remainder上做迭代。26 type item = &'a str;2728 fn next(&mut self) -> option {29 // 这里为什么用some(ref mut remainder),而不用some(&mut refmainder) ?30 if let some(ref mut remainder) = self.remainder {31 if let some(next_delim) = remainder.find(self.delimiter) {32 let until_remainder = &remainder[..next_delim];33 *remainder = &remainder[next_delim + self.delimiter.len()..];34 some(until_remainder)35 }else {36 self.remainder.take()37 }38 }else {39 none40 }41 }42}4344#[test]45fn it_works() {46 let haystack = a b c d e;47 let letters: vec = strsplit::new(haystack, ).collect();48 assert_eq!(letters, vec![a, b, c, d, e]);49}5051#[test]52fn tail() {53 let haystack = a b c d ;54 let letters: vec = strsplit::new(haystack, ).collect();55 assert_eq!(letters, vec![a, b, c, d, ]);56} 执行cargo test,测试通过:running 2 teststest str_split_2::tail ... oktest str_split_2::it_works ... ok 在上面代码的第30行,为什么用some(ref mut remainder),而不是用some(&mut refmainder)?这是因为在进行some(&mut remainder)=self.remainder模式匹配时,remainder会被自动解引用成str类型,而不是可变的&str类型。 另一种写法 1impl iterator for strsplit { 2 // 迭代的结果也要与strsplit拥有相同的生命周期,是因为要在strsplit的成员remainder上做迭代。 3 type item = &'a str; 4 5 fn next(&mut self) -> option { 6 // 为什么不可以这么写??? 7 let remainder = &mut self.remainder?; 8 if let some(next_delim) = remainder.find(self.delimiter) { 9 let until_remainder = &remainder[..next_delim];10 *remainder = &remainder[next_delim + self.delimiter.len()..];11 some(until_remainder)12 }else {13 self.remainder.take()14 }15 }16}17
在迭代器的next方法里尝试换一种写法,编译器检查通过,但是执行测试不通过。也就是上面代码的第7行,为什么不可以这么写?
self.remainder是option类型,这里的泛型是引用。所以在执行unwrap(),expect()或?时,会将option里的引用copy一份出来赋值给remainder,然后在这个新的remainder上作可变引用,而self.remainder没有任何变化。
我们可以使用option的as_mut()方法,因为它返回的是option:
1fn next(&mut self) -> option {2 // 为什么这么写不可以???3 // let remainder = &mut self.remainder?;45 let remainder = self.remainder.as_mut()?;6 ......7 }
得到了一个self.remainder的可变引用,因此测试通过。
在下一篇文章中,我们通过更多的例子来继续学习rust的生命周期。
阿布扎比港务公司正在采用区块链来提高航运与物流的效率
深度解析路虎全新发现底盘
使用Verilog/SystemVerilog硬件描述语言练习数字硬件设计
传苹果A7芯片今夏试生产 明年开始商业化量产
毫米波雷达的自适应波束成形技术:提升感知精度的前沿探索
CRust学习笔记:生命周期-1
如何解决制造企业数字化转型中的数据散乱和管理难题,实现顺利转型?
介绍一种基于功能核酸的微流控热泳生物传感器
《SUPERHOT VR》一周收入超200万美元 不支持与Oculus Rift交叉购买
太阳能+光伏浪涌保护器的选型方案
MG3633A大量特供MG3633A信号发生器/安立MG3633A
新版火车票二维码防伪技术
科沃斯商用在银行领域的落地应用策略
信号继电器作用是什么
VR、机器人、智能汽车:下一个独角兽会出自哪个风口?
低压断路器脱扣器的选择与整定
一大批前沿的科技产品都在向VR领域靠拢,VR大规模商业化爆发节点来临
适用于电流模式DC-DC转换器的统一的LTspice AC模型
MCU短缺正在下沉技术研发
新一代的USB 3.0外设控制器