MDGSF Software Engineer

[Rust] reference lifetime

2019-01-28

/*
&i32         // a reference
&'a i32      // a reference with an explicit lifetime
&'a mut i32  // a mutable reference with an explicit lifetime
*/

/*
lifetime annotation 是用来标记函数的输入参数和返回值之间的关系的。
如果输入参数和返回值之间没有借用关系,则不需要加 lifetime annotation。

longest 这个函数应用了所有的规则,都无法确定所有的生命周期,所以需要手动标注生命周期。
*/
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

/*
longest2 的返回值是一份拷贝,和输入参数没有关系,所有不用加 lifetime annotation。
*/
fn longest2(x: &str, y: &str) -> String {
    if x.len() > y.len() {
        x.to_string().clone()
    } else {
        y.to_string().clone()
    }
}

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

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

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

impl<'a> ImportantExcerpt<'a> {
    // announce_and_return_part 这个函数应用规则 1 和规则 3 可以确定所有的生命周期。
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

fn test2() {
    let noval = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = noval.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
    /*
    变量 i 中的 part 租借了 first_sentence,所以变量 i 的生命周期不能超过 first_sentence
    */
}

/*
first_word1 和 first_word2 都是合法的,因为 rust 的编译器能够自动推断出这种情况。
first_word1 这个函数应用规则 1 和规则 2 可以确定所有的生命周期。
*/
fn first_word1(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

fn first_word2<'a>(s: &'a str) -> &'a str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

/*
lifetime elision rule
当出现 lifetime elision rule 的情况时,rust 编译器就很可能能够自动推断出
函数的输入参数和返回值之间的生命周期关系。
函数参数中的生命周期叫做 input lifetimes
函数返回值中的生命周期叫做 output lifetimes

规则 1:函数的每个输入参数都拥有自己的生命周期标记。
    例如: fn foo<'a>(x: &'a i32);
    例如: fn foo<'a, 'b>(x: &'a i32, y: &'b i32);

规则 2:如果函数只有一个 input lifetime annotation ,那么把这个 input lifetime annotation 应用
    到所有的输出参数上。
    例如: fn foo<'a>(x: &'a i32) -> &'a i32;

规则 3:如果函数的多个参数中有一个是 &self 或者是 &mut self,那么把这个参数的
    input lifetime annotation 应用到所有的输出参数上。


注意:
    1. 只有租借的类型需要判断生命周期。
    2. 通过这 3 个规则检查之后,如果还无法确定所有的生命周期,rust 会报错,要求开发人员手动标注生命周期。

*/

fn main() {
    test1();
    test2();
}

reference_lifetime

https://kaisery.github.io/trpl-zh-cn/ch10-03-lifetime-syntax.html

https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html


weixingongzhonghao

Similar Posts

上一篇 [Rust] HashMap

Comments