0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

CRust学习笔记:生命周期-1

jf_wN0SrCdH 来源:coding到灯火阑珊 作者: 李明 2022-12-19 09:33 次阅读

本系列文章是Jon Gjengset发布的CRust of Rust系列视频的学习笔记,CRust of Rust是一系列持续更新的Rust中级教程

在这篇文章中,我们将研究一个需要显式注释多个生命期的例子。我们还将讨论不同字符串类型之间的一些差异,以及在自定义的trait上引入泛型。这个例子是根据给定的字符串和分隔符对字符串进行拆分。

创建一个新项目:

cargo new --lib strsplit
lib.rs中写入如下代码:
 1#[derive(Debug)]
 2pubstructStrSplit<'a>{
 3remainder:&'astr,
 4delimiter:&'astr,
 5}
 6
 7#[allow(dead_code)]
 8impl<'a>StrSplit<'a>{
 9pubfnnew(haystack:&'astr,delimiter:&'astr)->Self{
10Self{
11remainder:haystack,
12delimiter,
13}
14}
15}
16
17impl<'a>IteratorforStrSplit<'a>{
18typeItem=&'astr;
19
20fnnext(&mutself)->Option{
21ifletSome(next_delim)=self.remainder.find(self.delimiter){
22letuntil_remainder=&self.remainder[..next_delim];
23self.remainder=&self.remainder[next_delim+self.delimiter.len()..];
24Some(until_remainder)
25}elseifself.remainder.is_empty(){
26None
27}else{
28letrest=self.remainder;
29//为什么空字符串可以赋值给self.remainder???
30self.remainder="";
31Some(rest)
32}
33}
34}
35
36#[test]
37fnit_works(){
38lethaystack="abcde";
39letletters:Vec<_>=StrSplit::new(haystack,"").collect();
40assert_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]
2fntail(){
3lethaystack="abcd";
4letletters:Vec<_>=StrSplit::new(haystack,"").collect();
5assert_eq!(letters,vec!["a","b","c","d",""]);
6}
执行cargo test:
running 2 tests
test str_split_1::it_works ... ok
test str_split_1::tail ... FAILED
我们将struct StrSplit的成员remainder定义为Option<&'a str>类型来修复这个bug:
 1/**
 2*StrSplit与成员remainder,delimiter拥有相同的生命周期
 3*/
 4#[derive(Debug)]
 5pubstructStrSplit<'a>{
 6//使用Option
 7remainder:Option<&'a str>,
 8delimiter:&'astr,
 9}
10
11#[allow(dead_code)]
12impl<'a>StrSplit<'a>{
13/**
14*新构建的StrSplit与传入的参数haystack,delimiter拥有相同的生命周期
15*/
16pubfnnew(haystack:&'astr,delimiter:&'astr)->Self{
17Self{
18remainder:Some(haystack),
19delimiter,
20}
21}
22}
23
24impl<'a>IteratorforStrSplit<'a>{
25//迭代的结果也要与StrSplit拥有相同的生命周期,是因为要在StrSplit的成员remainder上做迭代。
26typeItem=&'astr;
27
28fnnext(&mutself)->Option{
29//这里为什么用Some(refmutremainder),而不用Some(&mutrefmainder)???
30ifletSome(refmutremainder)=self.remainder{
31ifletSome(next_delim)=remainder.find(self.delimiter){
32letuntil_remainder=&remainder[..next_delim];
33*remainder=&remainder[next_delim+self.delimiter.len()..];
34Some(until_remainder)
35}else{
36self.remainder.take()
37}
38}else{
39None
40}
41}
42}
43
44#[test]
45fnit_works(){
46lethaystack="abcde";
47letletters:Vec<_>=StrSplit::new(haystack,"").collect();
48assert_eq!(letters,vec!["a","b","c","d","e"]);
49}
50
51#[test]
52fntail(){
53lethaystack="abcd";
54letletters:Vec<_>=StrSplit::new(haystack,"").collect();
55assert_eq!(letters,vec!["a","b","c","d",""]);
56}
执行cargo test,测试通过:
running 2 tests
test str_split_2::tail ... ok
test str_split_2::it_works ... ok
在上面代码的第30行,为什么用Some(ref mut remainder),而不是用Some(&mut refmainder)?这是因为在进行Some(&mut remainder)=self.remainder模式匹配时,remainder会被自动解引用成str类型,而不是可变的&str类型。 另一种写法
 1impl<'a>IteratorforStrSplit<'a>{
 2//迭代的结果也要与StrSplit拥有相同的生命周期,是因为要在StrSplit的成员remainder上做迭代。
 3typeItem=&'astr;
 4
 5fnnext(&mutself)->Option{
 6//为什么不可以这么写???
 7letremainder=&mutself.remainder?;
 8ifletSome(next_delim)=remainder.find(self.delimiter){
 9letuntil_remainder=&remainder[..next_delim];
10*remainder=&remainder[next_delim+self.delimiter.len()..];
11Some(until_remainder)
12}else{
13self.remainder.take()
14}
15}
16}
17

在迭代器的next方法里尝试换一种写法,编译器检查通过,但是执行测试不通过。也就是上面代码的第7行,为什么不可以这么写?

self.remainder是Option<&'a str>类型,这里的泛型是引用。所以在执行unwrap(),expect()或?时,会将Option里的引用Copy一份出来赋值给remainder,然后在这个新的remainder上作可变引用,而self.remainder没有任何变化。

我们可以使用Option的as_mut()方法,因为它返回的是Option<&mut T>:

1fnnext(&mutself)->Option{
2//为什么这么写不可以???
3//letremainder=&mutself.remainder?;
4
5letremainder=self.remainder.as_mut()?;
6......
7}

得到了一个self.remainder的可变引用,因此测试通过。

在下一篇文章中,我们通过更多的例子来继续学习Rust的生命周期。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 字符串
    +关注

    关注

    1

    文章

    578

    浏览量

    20493
  • 生命周期
    +关注

    关注

    0

    文章

    15

    浏览量

    7459
  • Rust
    +关注

    关注

    1

    文章

    228

    浏览量

    6581

原文标题:CRust学习笔记:生命周期-1

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于Rust语言中的生命周期

    Rust是一门系统级编程语言具备高效、安和并发等特,而生命周期是这门语言中比较重要的概念之一。在这篇教程中,我们会了解什么是命周期、为什么需要生命周期、如何使用生命周期,同时我们依然会
    的头像 发表于 09-19 17:03 879次阅读

    AutoScaling 生命周期挂钩功能

    摘要: AutoScaling 伸缩组实例管理功能全面升级,新上线生命周期挂钩(LifecycleHook)功能,方便用户更加灵活地管理伸缩组内实例。使用生命周期挂钩可以在伸缩组发生伸缩活动时将伸缩
    发表于 06-27 17:13

    HarmonyOS应用开发-PageAbility生命周期

    pageAbility的生命周期如下图所示:在代码中通过调用下列方法实现生命周期操作:onShow() :Ability由后台不可见状态切换到前台可见状态调用onShow方法,此时用户在屏幕可以看到
    发表于 10-17 11:11

    在S32G2 RM中有“生命周期”,生命周期的完整含义是什么?

    在S32G2 RM中,有“生命周期”。生命周期的完整含义是什么,我们应该如何使用它?
    发表于 04-23 10:37

    一文读懂Android Activity生命周期

    正常情况下Activity的生命周期: Activity的生命周期大概可以归为三部分 整个的生命周期:onCreate()可以设置所有的“全局”状态, onDestory()可以释放所有的资源 可见
    发表于 05-30 01:03 1573次阅读

    基于延长WSN生命周期的LEACH算法的改进

    基于延长WSN生命周期的LEACH算法的改进(开关电源技术与设计pdf百度云)-基于延长WSN生命周期的LEACH算法的改进                    
    发表于 09-15 11:17 14次下载
    基于延长WSN<b class='flag-5'>生命周期</b>的LEACH算法的改进

    CRust学习笔记生命周期-2

    本系列文章是Jon Gjengset发布的CRust of Rust系列视频的学习笔记CRust of Rust是一系列持续更新的Rust中级教程。
    的头像 发表于 12-19 09:34 858次阅读

    CRust学习笔记:声明宏

    本系列文章是Jon Gjengset发布的CRust of Rust系列视频的学习笔记CRust of Rust是一系列持续更新的Rust中级教程。
    的头像 发表于 01-06 14:37 802次阅读

    CRust学习笔记:智能指针和内部可变性

    本系列文章是Jon Gjengset发布的CRust of Rust系列视频的学习笔记CRust of Rust是一系列持续更新的Rust中级教程。
    的头像 发表于 01-29 14:58 808次阅读

    Vue入门Vue的生命周期

    .生命周期 4.1生命周期是什么 Vue的生命周期, 就是Vue实例从创建到销毁的过程.
    的头像 发表于 02-06 16:16 851次阅读
    Vue入门Vue的<b class='flag-5'>生命周期</b>

    编译器的标准生命周期

    编译器的标准生命周期
    发表于 03-14 19:06 0次下载
    编译器的标准<b class='flag-5'>生命周期</b>

    编译器的标准生命周期

    编译器的标准生命周期
    发表于 07-05 19:32 1次下载
    编译器的标准<b class='flag-5'>生命周期</b>

    数据包的生命周期

    电子发烧友网站提供《数据包的生命周期.pdf》资料免费下载
    发表于 10-13 14:44 0次下载

    鸿蒙开发:【PageAbility的生命周期

    PageAbility生命周期是PageAbility被调度到INACTIVE、ACTIVE、BACKGROUND等各个状态的统称。PageAbility生命周期流转及状态说明见如下图1、表1
    的头像 发表于 06-17 10:05 674次阅读
    鸿蒙开发:【PageAbility的<b class='flag-5'>生命周期</b>】

    鸿蒙开发组件:DataAbility的生命周期

    应用开发者可以根据业务场景实现data.js/data.ets中的生命周期相关接口。DataAbility生命周期接口说明见下表。
    的头像 发表于 06-20 09:39 413次阅读