关于rust:rust学习生命周期

4次阅读

共计 5394 个字符,预计需要花费 14 分钟才能阅读完成。

说生命周期,最经典的莫属空指针问题了:

fn main() {
    {
        let r;

        {
            let x = 5;
            r = &x;
        }

        println!("r: {}", r);
    }
}

能够看到 x 的作用域在打印之前就曾经不起作用了,然而 r 对其进行了一个援用,所以在打印出仍旧须要应用 x,因而就造成了空指针问题。解决办法就是转移将 x 的所属权,比方:r = x;

吐槽一下所有权,所有权并不是说变量被所有了,而是变量所指向的值被变量独自所领有,被别的变量借走了就变成了别的了,就不再领有所有权了。

来看一个实例,比方咱们比拟两个字符串那个长度更短暂返回那个,咱们可能这样编写程序:

fn main() {let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

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

看似没有问题,然而当咱们运行的时候会发现:

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
error[E0106]: missing lifetime specifier
 --> src\main.rs:9:33
  |
9 | fn longest(x: &str, y: &str) -> &str {
  |               ----     ----     ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
  |
9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  |           ^^^^    ^^^^^^^     ^^^^^^^     ^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0106`.
error: could not compile `cargo_learn`.

To learn more, run the command again with --verbose.

程序报错了。错误信息竟然是编译的时候查看到返回的值要有所有权也就是要返回一个在生命周期中的值的变量。就像之前的空指针问题一样,所以咱们须要在返回和入参的时候思考到是否能够把生命周期也就是所有权也传入和返回呢,当然能够,谬误提醒中曾经给到了解决办法。

先来看一下 rust 中含有生命周期援用的办法(‘ + 一个小写字母):

&i32        // 一般援用
&'a i32     // 含有生命周期的援用
&'a mut i32 // 可变形含有生命周期的援用

如此咱们就能够很轻松地革新下面的例子:

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

运行后果为:

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.72s
     Running `target\debug\cargo_learn.exe`
The longest string is abcd

然而不管怎样,生命周期毕竟是比拟有意思的,比方咱们将 main 函数改写一下:

fn main() {let string1 = String::from("long string is long");
    let result;
    {let string2 = String::from("xyz");
        result = longest(string1.as_str(), string2.as_str());
    }
    println!("The longest string is {}", result);
}

那么运行后果就变成了:

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
error[E0597]: `string2` does not live long enough
 --> src\main.rs:6:44
  |
6 |         result = longest(string1.as_str(), string2.as_str());
  |                                            ^^^^^^^ borrowed value does not live long enough
7 |     }
  |     - `string2` dropped here while still borrowed
8 |     println!("The longest string is {}", result);
  |                                          ------ borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: could not compile `cargo_learn`.

To learn more, run the command again with --verbose.

与之相应的一个变例(其实都跟最开始的小示例相似):

fn main() {let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest<'a>(x: &str, y: &str) -> &'a str {let result = String::from("really long string");
    result.as_str()}
D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
warning: unused variable: `x`
 --> src\main.rs:9:16
  |
9 | fn longest<'a>(x: &str, y: &str) -> &'a str {
  |                ^ help: if this is intentional, prefix it with an underscore: `_x`
  |
  = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `y`
 --> src\main.rs:9:25
  |
9 | fn longest<'a>(x: &str, y: &str) -> &'a str {
  |                         ^ help: if this is intentional, prefix it with an underscore: `_y`

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

error: aborting due to previous error; 2 warnings emitted

For more information about this error, try `rustc --explain E0515`.
error: could not compile `cargo_learn`.

To learn more, run the command again with --verbose.

以上阐明了一个事实,如果含有生命周期援用和返回的变量值只在跟起相干的所有变量都有成果的状况下才无效否则生效.

构造体中应用字符串切片援用
之前所有的例子中返回的都是 String 并没有字符串切片 &str 类型的,当初来看其实曾经很简略因为 &str 只是 String 的一个局部援用,所以当 String 生效的时候其必然失去了生命周期,因而出错,那么当初就能够来解决该问题了:

fn main() {
    struct Str<'a> {content: &'a str}
    let s = Str {content: "string_slice"};
    println!("s.content = {}", s.content);
}

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.53s
     Running `target\debug\cargo_learn.exe`
s.content = string_slice

应用泛型情景

fn first_word<'a>(s: &'a str) -> &'a str {fn foo<'a,'b>(x: &'a i32, y: &'b i32) -> &'c i32 {fn first_word(s: &str) -> &str {fn first_word<'a>(s: &'a str) -> &str {fn first_word<'a>(s: &'a str) -> &'a str {

办法定义中的生命周期正文

struct ImportantExcerpt<'a> {part: &'a str,}

impl<'a> ImportantExcerpt<'a> {fn level(&self) -> i32 {3}
}

impl<'a> ImportantExcerpt<'a> {fn announce_and_return_part(&self, announcement: &str) -> &str {println!("Attention please: {}", announcement);
        self.part
    }
}

fn main() {let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a'.'");
    let i = ImportantExcerpt {part: first_sentence,};
}

要求在 impl 之后申明生命周期参数,并在类型名称后应用它,然而因为第一个省略规定,咱们不须要正文对 self 的援用的生命周期。

这是第三个生命周期删除规定实用的示例:

impl<'a> ImportantExcerpt<'a> {fn announce_and_return_part(&self, announcement: &str) -> &str {println!("Attention please: {}", announcement);
        self.part
    }
}

动态生命周期:

生命周期正文有一个特地的:'static 。所有用双引号包含的字符串常量所代表的准确数据类型都是 &'static str'static 所示意的生命周期从程序运行开始到程序运行完结。

例如:let s: &'static str =" 我是一个动态生命周期 ";

泛型,特色,生命周期在一起:

fn main() {let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest_with_an_announcement(string1.as_str(),
        string2,
        "Today is someone's birthday!",
    );
    println!("The longest string is {}", result);
}

use std::fmt::Display;

fn longest_with_an_announcement<'a, T>(
    x: &'a str,
    y: &'a str,
    ann: T,
) -> &'a str
    where
        T: Display,
{println!("Announcement! {}", ann);
    if x.len() > y.len() {x} else {y}
}

运行后果:

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.65s
     Running `target\debug\cargo_learn.exe`
Announcement! Today is someone's birthday!
The longest string is abcd
正文完
 0