当前位置: 首页 > news >正文

深圳品牌网站建设深圳搜索引擎优化推广

深圳品牌网站建设,深圳搜索引擎优化推广,公司注册网上核名业务如何终止,山东省通信管理局 对于经营性网站的认定喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 10.7.1. 深入理解生命周期 1.指定生命周期参数的方式依赖于函数所做的事情 以上一篇文章的…

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

10.7.1. 深入理解生命周期

1.指定生命周期参数的方式依赖于函数所做的事情

以上一篇文章的代码为例子:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {  if x.len() > y.len() {  x  } else {  y  }  
}

这里的函数签名之所以这么写是因为不确定返回值到底是x还是y。如果我修改代码,比如把返回值固定为x那么就没必要给y写一个显式生命周期了:

fn longest<'a>(x: &'a str, y: &str) -> &'a str {  x
}

所以这个代码的函数签名就没有给y限制生命周期。

2.当函数返回引用时,返回类型的生命周期参数需要与其中一个生命周期匹配

如果返回的引用没有指向任何参数,返回的内容就会变成悬空引用,因为在函数内创建的值在函数结束的时候就离开了作用域,返回的引用指向的就是被释放的内存。

看个例子:

fn longest<'a>(x: &'a str, y: &str) -> &'a str {  let result = String::from("Something");result.as_str()
}

在这个函数里创建了一个String类型的result,然后调用result上的as_str方法返回字符串切片(&str),其实就是一个引用,然后就报错了:

error[E0515]: cannot return value referencing local variable `result`--> src/main.rs:13:5|
13 |     result.as_str()|     ------^^^^^^^^^|     ||     returns a value referencing data owned by the current function|     `result` is borrowed here

报错信息是无法返回引用本地变量result的值,因为这块返回的值是函数内部持有的数据,其实就是刚才说的原因,当内部数据离开作用域后就会被清除。

那如果我就想要把函数内部创建值作为返回值改怎么写呢?那就不返回引用,直接返回这个值:

fn longest(x: &str, y: &str) -> String {  let result = String::from("Something");result
}

这样就相当于把函数的所有权移交给调用者了,要清理这块内存就由调用者来清理。这样写也不需要显式声明声明周期了,因为返回值与参数根本没关系,而且只有引用才有生命周期问题。

通过这个例子可以看到,生命周期的语法在根本上就是用来关联函数的不同参数以及返回值之间的生命周期的。 一旦它们取得了某种联系,Rust就获得了足够的信息来支持保证内存安全的操作并且组织可能会导致悬垂指针或是其他破坏内存安全的操作。

10.7.2. 结构体中的生命周期标注

在前面的文章里,我们在结构体中只定义过自持有的类型,比如i32String。而实际上结构体的字段也可以是引用类型,如果是引用的话就需要在每个引用上添加生命周期标注。

看个例子:

struct ImportantExcerpt<'a> {part: &'a str,
}fn main() {let novel = String::from("Call me Ishmael. Some years ago...");let first_sentence = novel.split('.').next().unwrap();let i = ImportantExcerpt {part: first_sentence,};
}

ImportantExcerpt下只有一个字段part,其类型是字符串切片,也就是一个引用类型。因为它是引用类型,所以就需要标注生命周期。

生命周期标注的方法和泛型一样,就在结构体后面加<>,在里面写生命周期泛型类型参数即可,这里写的是'apart这个引用必须要比这个结构体实例的存活时间要长。因为只要实例存在,就会一直有part这个引用,如果part先没有,那么实例肯定会出错。

main函数,里面先创建了一个String类型的novel然后通过splitnext方法来提取出这个字符串里的第一个句子(unwrap是用来解包Option类型的,在 9.2. Result枚举与可恢复的错误 Pt.1 中有过介绍)。这个句子的类型是&str,也就是一个引用。然后创建了ImportantExcerpt这一结构体的实例i,把这个引用作为part字段的值。

这样写是没有错误的,因为first_sentence这个引用的作用域是从第7行到第11行,而i的作用域是从第8行到第11行,所以说part这个字段的存活时间比实例长并且能完全覆盖i的生命周期。

10.7.3. 生命周期的省略

每个引用都有生命周期,并且需要为使用生命周期的函数或结构体指定生命周期参数。

那为什么这段代码(来自 4.5. 切片(Slice))没有生命周期也能通过编译呢:

fn main() {let s = String::from("Hello world");let word = first_word(&s);println!("{}", word);
}
fn first_word(s:&str) -> &str {let bytes = s.as_bytes();for (i, &item) in bytes.iter().enumerate() {if item == b' ' {return &s[..i];} }&s[..]
}

这个函数在没有生命周期注释的情况下编译的原因是有历史的:在 Rust 的早期版本(1.0 之前)中,这个代码不会通过编译,因为当时要求每个引用都需要一个显式的生命周期。函数签名就得这样写:

fn first_word<'a>(s: &'a str) -> &'a str {

后来Rust团队发现在某些特定情况下Rust程序员总会一遍又一遍地写同样的生命周期标注,而且这些场景是可预测的,这些场景有一些明确的模式,于是Rust团队就将这些模式直接写入了编译器代码,使得借用检查器在这些情况下可以自动地推导生命周期,而无需程序员显式标注。

了解这段历史的意义在于未来可能会有更多确定性模式可能会出现并被添加到编译器中。将来,可能需要更少的生命周期注释(谢天谢地)。

刚才说的这些在Rust引用分析中所编入的模式称为生命周期省略规则。这些规则无需程序员来遵守,它们是一些特殊情况,由编译器来考虑。如果你的代码符合这些情况,那就无需显式标注生命周期。

但是生命周期省略规则不会提供完整的推断,如果在应用了这个规则以后,引用的生命周期仍然模糊不清,那么仍然会引发编译错误。解决办法就是手动添加生命周期,表明引用间的相互关系。

10.7.4. 输入、输出生命周期

如果生命周期出现在函数/方法的参数中,那么这类生命周期就叫做输入生命周期

如果它出现在函数/方法的返回值中,那么就叫做输出生命周期

10.7.5. 生命周期省略的三个规则

编译器使用3个规则在没有显式标注生命周期的情况下来确定引用的生命周期

  • 规则1用于输入生命周期
  • 规则2、3用于输出生周期
  • 如果编译器在应用完3个规则后仍然有无法确定生命周期的引用,就会报错
  • 这3个规则不但适用于函数或是方法的定义,也适用于impl

规则1: 每个引用类型的参数都有自己的生命周期。 单参数的函数就有1个生命周期,双参数的函数就有两个,以此类推。

规则2: 如果只有1个输入生命周期参数,那么该生命周期被赋给所有的输出生命周期参数。 就是单参数的生命周期只有1个,这个生命周期就是这个函数所有可能返回值的生命周期。

规则3: 如果有多个输入生命周期参数,但其中一个是&self&mut self(也就是说是这个函数是方法),那么self的生命周期会被赋给所有输出的生命周期参数。

1. 成功例

规则讲完,看看例子:

fn first_word(s:&str) -> &str {//...
}

把自己带入一下编译器,想想对于这个函数签名如何根据3条规则来找到省略的生命周期。

首先应用第一条规则——每个引用类型的参数都有自己的生命周期。这里只有一个参数,所以就只有一个生命周期。所以到这一步编译器推断出了:

fn first_word<'a>(s:&'a str) -> &str {//...
}

由于只有一个输入生命周期,所以第2条规则在这里也适用——如果只有1个输入生命周期参数,那么该生命周期被赋给所有的输出生命周期参数。 所以输入生命周期就被赋予给了输出生命周期。到这一步编译器推断出了:

fn first_word<'a>(s:&'a str) -> &'a str {//...
}

由于只有一个输入生命周期,且这个函数不是方法,所以第3条不适用

而现在函数中所有的引用都有了生命周期,因此编译器就可以继续分析代码,而无需程序员手动标注这个函数签名里的生命周期。

2. 失败例

来看第二个例子:

fn longest(x:&str, y:&str) -> &str {//...
}

这个函数签名有两个引用输入,返回类型也是引用。尝试用这3条规则:

首先应用第一条规则——每个引用类型的参数都有自己的生命周期。这里有两个参数,就有两个生命周期:

fn longest<'a, 'b>(x:&'a str, y:&'b str) -> &str {//...
}

由于有两个引用参数,所以规则2不适用。

由于这个函数不是方法,所以规则3不适用。

应用完这3条规则后发现返回值的生命周期仍然无法确定,所以编译器就会报错。也就是说你必须显式声明生命周期。

http://www.fp688.cn/news/164101.html

相关文章:

  • 怎么建设一个电影网站培训seo去哪家机构最好
  • wordpress怎么做伪静态sem和seo有什么区别
  • 做淘宝网站需要成人职业技能培训有哪些项目
  • 上海商城网站建设兰州模板网站seo价格
  • wordpress 评论 设置网站seo文章
  • 网站建设phpweb教程网上怎么免费推广
  • 温州建设局官方网站网络推广一个月的收入
  • 郑州公司做网站汉狮公司想做个网站怎么办
  • 登不上学校的网站该怎么做seo怎样才能优化网站
  • 企业网站制作建设外贸推广公司
  • 淮安网站制作设计网站申请流程
  • 关于加强企业门户网站建设通知活动营销推广方案
  • 贵阳做网站的大公司有哪些东莞seo网站制作报价
  • 北京哪家做网站和网络推广好的站内优化怎么做
  • 建设对公银行网站打不开重庆seo排
  • 哪个网站可以做市场调研报告网站模板之家官网
  • 怎么做动漫原创视频网站创建自己的网页
  • 公司网站建设建议书株洲发布最新通告
  • pc网站建设意见长沙网络推广平台
  • 客户评价网站建设seo关键词排名技术
  • 网站建设服务属于信息技术服务吗郑州seo技术服务顾问
  • 建网站地址新闻软文发布平台
  • 娄底网站优化临沂seo优化
  • 为什么网站关键词没有排名域名收录查询
  • 网推网站百度推广价格价目表
  • vs做的小型网站例传媒网站
  • 东莞网站建设是什么江苏网站推广公司
  • php整站最新版本下载免费网站推广软件
  • 湖南网站建设制作网站排名优化推广
  • wordpress获取图片的绝对地址seo外包服务专家