是否可能有一个结构,该结构包含对寿命短于该结构的值的引用? [英] Is it possible to have a struct which contains a reference to a value which has a shorter lifetime than the struct?

查看:101
本文介绍了是否可能有一个结构,该结构包含对寿命短于该结构的值的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我要存档的简化版本:

Here is a simplified version of what I want to archive:

struct Foo<'a> {
    boo: Option<&'a mut String>,
}

fn main() {
    let mut foo = Foo { boo: None };
    {
        let mut string = "Hello".to_string();
        foo.boo = Some(&mut string);
        foo.boo.unwrap().push_str(", I am foo!");
        foo.boo = None;
    } // string goes out of scope. foo does not reference string anymore

} // foo goes out of scope

这显然是完全安全的,因为一旦string超出范围,foo.boo就是None.

This is obviously completely safe as foo.boo is None once string goes out of scope.

有没有办法告诉编译器?

Is there a way to tell this to the compiler?

推荐答案

这显然是完全安全的

This is obviously completely safe

对于人类而言,显而易见的对编译器而言并不总是显而易见的.有时,编译器不如人类聪明(但是要更加警惕!).

What is obvious to humans isn't always obvious to the compiler; sometimes the compiler isn't as smart as humans (but it's way more vigilant!).

在这种情况下,启用非词法生存期时,原始代码会编译:

In this case, your original code compiles when non-lexical lifetimes are enabled:

#![feature(nll)]

struct Foo<'a> {
    boo: Option<&'a mut String>,
}

fn main() {
    let mut foo = Foo { boo: None };
    {
        let mut string = "Hello".to_string();
        foo.boo = Some(&mut string);
        foo.boo.unwrap().push_str(", I am foo!");
        foo.boo = None;
    } // string goes out of scope. foo does not reference string anymore

} // foo goes out of scope

这仅是 ,因为一旦foo无效(在string超出范围后),就永远不会使用它,不是,因为您将值设置为None.尝试在最里面的作用域之后打印出该值仍然会导致错误.

This is only because foo is never used once it would be invalid (after string goes out of scope), not because you set the value to None. Trying to print out the value after the innermost scope would still result in an error.

是否可能有一个结构,该结构包含对一个比该结构寿命短的值的引用?

Is it possible to have a struct which contains a reference to a value which has a shorter lifetime than the struct?

Rust借用系统的目的是为了确保拥有引用的事物的寿命不会长于所引用项目的寿命.

The purpose of Rust's borrowing system is to ensure that things holding references do not live longer than the referred-to item.

也许吧,只要您在引用不再有效之后就不要使用.例如,这可行:

Maybe, so long as you don't make use of the reference after it is no longer valid. This works, for example:

#![feature(nll)]

struct Foo<'a> {
    boo: Option<&'a mut String>,
}

fn main() {
    let mut foo = Foo { boo: None };
    // This lives less than `foo`
    let mut string1 = "Hello".to_string();
    foo.boo = Some(&mut string1); 
    // This lives less than both `foo` and `string1`!
    let mut string2 = "Goodbye".to_string();
    foo.boo = Some(&mut string2); 
}

在非词汇生存期之前

不.借阅检查器不够聪明,无法告诉您在无效之后不能/不使用引用.太保守了.

Before non-lexical lifetimes

No. The borrow checker is not smart enough to tell that you cannot / don't use the reference after it would be invalid. It's overly conservative.

在这种情况下,您会遇到这样的事实:生存期被表示为类型的一部分.换句话说,通用寿命参数 'a已填充"了具体寿命值,该值覆盖了string处于活动状态的行.但是,foo的生存期比那些行更长,因此会出现错误.

In this case, you are running into the fact that lifetimes are represented as part of the type. Said another way, the generic lifetime parameter 'a has been "filled in" with a concrete lifetime value covering the lines where string is alive. However, the lifetime of foo is longer than those lines, thus you get an error.

编译器不会查看您的代码采取了什么操作;一旦看到您使用该特定生存期对其进行了参数化,便是如此.

The compiler does not look at what actions your code takes; once it has seen that you parameterize it with that specific lifetime, that's what it is.

我通常要解决的问题是将类型分为两部分,即需要引用的部分和不需要引用的部分.

The usual fix I would reach for is to split the type into two parts, those that need the reference and those that don't:

struct FooCore {
    size: i32,
}

struct Foo<'a> {
    core: FooCore, 
    boo: &'a mut String,
}

fn main() {
    let core = FooCore { size: 42 };
    let core = {
        let mut string = "Hello".to_string();
        let foo = Foo { core, boo: &mut string };
        foo.boo.push_str(", I am foo!");
        foo.core        
    }; // string goes out of scope. foo does not reference string anymore

} // foo goes out of scope

请注意,这如何消除了对Option的需求-您的类型现在会告诉您字符串是否存在.

Note how this removes the need for the Option — your types now tell you if the string is present or not.

另一种解决方案是在设置字符串时映射整个类型.在这种情况下,我们将使用整个变量并通过更改生命周期来更改类型:

An alternate solution would be to map the whole type when setting the string. In this case, we consume the whole variable and change the type by changing the lifetime:

struct Foo<'a> {
    boo: Option<&'a mut String>,
}

impl<'a> Foo<'a> {
    fn set<'b>(self, boo: &'b mut String) -> Foo<'b> {
        Foo { boo: Some(boo) }
    }

    fn unset(self) -> Foo<'static> {
        Foo { boo: None }
    }
}

fn main() {
    let foo = Foo { boo: None };
    let foo = {
        let mut string = "Hello".to_string();
        let mut foo = foo.set(&mut string);
        foo.boo.as_mut().unwrap().push_str(", I am foo!");
        foo.unset()
    }; // string goes out of scope. foo does not reference string anymore

} // foo goes out of scope

这篇关于是否可能有一个结构,该结构包含对寿命短于该结构的值的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆