繁体   English   中英

Rust中的生命周期注释是否会改变变量的生命周期?

[英]Do lifetime annotations in Rust change the lifetime of the variables?

Rust 章节指出注释不会篡改变量的生命周期,但这有多正确? 根据这本书,函数longest接受两个字符串的引用并返回较长的字符串。 但是在错误的情况下

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

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);
}

它实际上确实改变了结果变量的生命周期,不是吗?

我们告诉Rust,最长函数返回的引用的生命周期与传入的引用的生命周期中的较小者相同。

本书仅提出的内容是函数的生命周期参数不会干扰受影响的值的生命周期。 他们不能使价值比计划已经规定的更长寿(或相反)。

但是,不同的功能签名可以决定这些引用的生命周期 由于引用在其生命周期中是协变的,因此您可以在该生命周期内将“更宽”的生命周期的引用转换为更小的生命周期。

例如,给定定义

fn longest<'a>(a: &'a str, b: &'a str) -> &'a str

,两个输入引用的生命周期必须匹配。 但是,我们可以这样写:

let local = "I am local string.".to_string();

longest(&local, "I am &'static str!");

字符串文字具有'static生命周期”,与生命周期'a兼容,在这种情况下主要受字符串local约束。

同样,在上面的示例中,生命周期'a必须被约束到嵌套字符串string2 ,否则它不能通过引用传递给函数。 这也意味着输出引用受此生命周期的限制,这就是为什么代码在尝试使用string2范围之外的longest输出时无法编译的原因:

error[E0597]: `string2` does not live long enough
  --> src/main.rs:14:44
   |
14 |         result = longest(string1.as_str(), string2.as_str());
   |                                            ^^^^^^^ borrowed value does not live long enough
15 |     }
   |     - `string2` dropped here while still borrowed
16 |     println!("The longest string is {}", result);
   |                                          ------ borrow later used here

有关生命周期及其协方差/逆变特征的扩展解释,请参阅此问题:

首先,了解生命周期和范围之间的区别非常重要。 引用具有生命周期,这取决于它们所引用的变量的范围。

变量范围是词法:

fn main() {
    let string1 = String::from("long string is long"); // <-- scope of string1 begins here
    let result;
    {
        let string2 = String::from("xyz"); // <-- scope of string2 begins here
        result = longest(string1.as_str(), string2.as_str());
        // <-- scope of string2 ends here
    }
    println!("The longest string is {}", result);
    // <-- scope of string1 ends here
}

创建对变量的新引用时,引用的生命周期仅与变量的范围相关联。 其他引用附加了不同的生命周期信息,具体取决于引用的来源以及该上下文中已知的信息。 将命名生命周期注释放在类型上时,类型检查器只是确保附加到任何引用的生命周期信息与注释兼容。

fn main() {
    let string1 = String::from("long string is long");
    let result;
    {
        let string2 = String::from("xyz");
        // The lifetime of result cannot be longer than `'a` 
        result = longest(string1.as_str(), string2.as_str());
        // But a reference to string2 also has lifetime `'a`, which means that
        // the lifetime `'a` is only valid for the scope of string2 
        // <-- i.e. to here
    }
    // But then we try to use it here — oops!
    println!("The longest string is {}", result);
}

我们告诉Rust,最长函数返回的引用的生命周期与传入的引用的生命周期中的较小者相同。

有点。 我们确实告诉了Rust这个信息,然而,借用检查器仍然会检查它是否属实! 如果它是不是已经真的,那么我们会得到一个错误。 我们不能改变那些信息的真实性,我们只能告诉Rust我们想要的限制,它会告诉我们我们是否正确。

在您的示例中,您可以通过更longest更改生命周期注释来使main函数有效:

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

但是现在你得到一个longest的错误因为它不再满足要求:它现在永远不会有效返回y因为它的生命周期可能比'a短。 实际上,正确实现此功能的唯一方法是:

  1. 返回x
  2. 返回一片x
  3. 返回&'static str - 因为'static超过所有其他生命周期
  4. 使用unsafe代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM