是否有可能有一个结构包含对生命周期比结构短的值的引用?

lnc*_*ncr 4 struct lifetime rust

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

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
Run Code Online (Sandbox Code Playgroud)

这显然是完全安全的,foo.booNone一次string去的范围了。

有没有办法告诉编译器?

She*_*ter 5

这显然是完全安全的

对人类显而易见的东西对编译器来说并不总是显而易见的。有时编译器不像人类那么聪明(但它更加警惕!)。

在这种情况下,当启用非词法生命周期时,您的原始代码会编译:

#![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
Run Code Online (Sandbox Code Playgroud)

只是因为foo从未使用过它会无效(string超出范围后),而不是因为您将值设置为None. 尝试在最里面的范围之后打印出值仍然会导致错误。

是否有可能有一个结构包含对生命周期比结构短的值的引用?

Rust 借用系统的目的是确保持有引用的事物不会比被引用的项目存活时间更长。

在非词法生命周期之后

也许,只要您在参考不再有效后不使用它。这有效,例如:

#![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); 
}
Run Code Online (Sandbox Code Playgroud)

在非词法生命周期之前

不。借用检查器不够聪明,无法告诉您不能/不要使用无效的参考资料。太保守了。

在这种情况下,您会遇到这样一个事实,即生命周期被表示为类型的一部分。换句话说,通用生命周期参数 'a已经被“填充”了一个具体的生命周期值,覆盖了string活着的行。但是,的生命周期foo比那些行长,因此您会收到错误消息。

编译器不会查看您的代码采取了哪些操作;一旦它看到你用那个特定的生命周期参数化它,那就是它。


我要达到的通常解决方法是将类型分成两部分,需要引用的部分和不需要引用的部分:

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
Run Code Online (Sandbox Code Playgroud)

请注意这如何消除对Option- 您的类型现在告诉您字符串是否存在的需要。

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

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
Run Code Online (Sandbox Code Playgroud)

  • 注意:如果不是微不足道的,最好通过引用传递 `FooCore`。 (3认同)
  • @Cthutu [已解决](https://play.rust-lang.org/?gist=e0ba85f9e74a64cd3318c08c8dd4b56e&amp;version=stable&amp;mode=debug)。[已解决](https://gist.github.com/d2965c155b891e83b6c56f7b651957a6)。[已解决](https://play.rust-lang.org/?gist=3ec722e5e415f64bcefb91514a438917&amp;version=nightly&amp;mode=debug)。我不明白你要通过威胁不推荐 Rust 来完成什么。如果 Rust 不适合您的情况,或者您无法理解,*没关系*。并非一切都适合每个人——使用对你来说舒服的东西,让你做你需要做的事情。 (2认同)