rust - 是否有可能有一个结构引用了一个生命周期可以更短的子结构?

标签 rust

我想用 Rust 编写这个 C++ 的等价物:

struct Bar { int x; };
struct Foo { Bar* bar; };

void main() {
    Bar bar { 42 };
    Foo foo { &bar };

    Bar bar2 { 50 };

    foo.bar = &bar2;
    printf("%d\n", foo.bar->x);
}

C++ 建立一个结构,然后用另一个 Bar 对象交换一个 Bar 对象。这是我试过的代码:

struct Bar(isize);
impl Bar {
    fn new(i: isize) -> Bar { Bar(i) }
}

struct Foo<'a> {
    bar: Option<&'a Bar>,
}
impl<'a> Foo<'a> {
    fn new(bar: &Bar) -> Foo {
        Foo { bar: Some(&bar) }
    }
}

fn main() {
    // Set up first state
    let bar = Bar::new(42);
    let mut foo = Foo::new(&bar);

    // Replace bar object
    let bar2 = Bar::new(50);
    foo.bar = Some(&bar2);

    if let Some(e) = foo.bar {
        println!("{}", e.0);
    }
}

此代码提示:

error[E0597]: `bar2` does not live long enough
  --> src/main.rs:22:21
   |
22 |     foo.bar = Some(&bar2);
   |                     ^^^^ borrowed value does not live long enough
...
27 | }
   | - `bar2` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

在 Rust 中是否可能有一个结构引用了一个生命周期可以更短的子结构(即,您可以用另一个实例替换子结构实例)?

我看了一些其他答案,并尝试拆分结构:

struct Bar(isize);
impl Bar {
    fn new(i: isize) -> Bar {
        Bar(i)
    }
}

struct FooCore {
    a: isize,
}

struct Foo<'c, 'a> {
    core: &'c FooCore,
    bar: &'a Bar,
}
impl<'c, 'a> Foo<'c, 'a> {
    fn new(core: &'c FooCore, bar: &'a Bar) -> Foo<'c, 'a> {
        Foo {
            core: &core,
            bar: &bar,
        }
    }
}

fn main() {
    // Set up first state
    let core = FooCore { a: 10 };
    let bar = Bar::new(42);
    let _foo = Foo::new(&core, &bar);

    // Replace bar object
    let bar2 = Bar::new(50);
    let foo = Foo::new(&core, &bar2);

    println!("{} {}", foo.core.a, foo.bar.0);
}

这可以编译并工作,但是,一旦我将 core 和 bar 字段设置为可变,它就会崩溃。下面是使用 mut 的代码:

#![allow(unused_mut)]

struct Bar(isize);
impl Bar {
    fn new(i: isize) -> Bar {
        Bar(i)
    }
}

struct FooCore {
    a: isize,
}

struct Foo<'c, 'a> {
    core: &'c mut FooCore,
    bar: &'a mut Bar,
}
impl<'c, 'a> Foo<'c, 'a> {
    fn new(core: &'c mut FooCore, bar: &'a mut Bar) -> Foo<'c, 'a> {
        Foo {
            core: &mut core,
            bar: &mut bar,
        }
    }
}

fn main() {
    // Set up first state
    let mut core = FooCore { a: 10 };
    let mut bar = Bar::new(42);
    let mut _foo = Foo::new(&mut core, &mut bar);

    // Replace bar object
    let mut bar2 = Bar::new(50);
    let mut foo = Foo::new(&mut core, &mut bar2);

    println!("{} {}", foo.core.a, foo.bar.0);
}

这会导致错误:

error[E0597]: `core` does not live long enough
  --> src/main.rs:21:24
   |
21 |             core: &mut core,
   |                        ^^^^ borrowed value does not live long enough
...
24 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'c as defined on the impl at 18:1...
  --> src/main.rs:18:1
   |
18 | impl<'c, 'a> Foo<'c, 'a> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0597]: `bar` does not live long enough
  --> src/main.rs:22:23
   |
22 |             bar: &mut bar,
   |                       ^^^ borrowed value does not live long enough
23 |         }
24 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 18:1...
  --> src/main.rs:18:1
   |
18 | impl<'c, 'a> Foo<'c, 'a> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0499]: cannot borrow `core` as mutable more than once at a time
  --> src/main.rs:35:33
   |
31 |     let mut _foo = Foo::new(&mut core, &mut bar);
   |                                  ---- first mutable borrow occurs here
...
35 |     let mut foo = Foo::new(&mut core, &mut bar2);
   |                                 ^^^^ second mutable borrow occurs here
...
38 | }
   | - first borrow ends here

我如何构建我的数据以实现我想要的?

最佳答案

明显的问题是您不必要地引用了引用:

在这段代码中,corebar已经是引用了,所以不需要获取它的地址:

impl<'c, 'a> Foo<'c, 'a> {
    fn new(core: &'c mut FooCore, bar: &'a mut Bar) -> Foo<'c, 'a> {
        Foo {
            core: &mut core,
            bar: &mut bar,
        }
    }
}

改为:

impl<'c, 'a> Foo<'c, 'a> {
    fn new(core: &'c mut FooCore, bar: &'a mut Bar) -> Foo<'c, 'a> {
        Foo {
            core: core,
            bar: bar,
        }
    }
}

关于子对象的生命周期比主对象长,一般的回答是“不,你不能”,因为引用可能会悬空而 Rust 不允许这样做。有一些解决方法,如上面评论中的链接答案所示。

作为模拟 C 代码的额外解决方法,您可以编写:

fn main() {
    // Set up first state
    let mut core = FooCore { a: 10 };
    let mut bar = Bar::new(42);
    let mut bar2; //lifetime of bar2 is greater than foo!
    let mut foo = Foo::new(&mut core, &mut bar);

    bar2 = Bar::new(50); //delayed initialization
    // Replace bar object
    foo.bar = &mut bar2;

    println!("{} {}", foo.core.a, foo.bar.0);
}

关于rust - 是否有可能有一个结构引用了一个生命周期可以更短的子结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50591935/

相关文章:

rust - 如何为具有特殊情况的枚举实现 `Hash`?

rust - 具有任意常量表达式的 cfg 属性

rust - 有没有办法在匹配中使用自定义模式,例如正则表达式或函数?

generics - 正确地为迭代器全面实现 argmax 特性

rust - 为什么我的 Future 实现一开始就陷入困境?

pointers - 解释 Rust 中的 C 声明

enums - 如何使用负整数哨兵值而不产生内存损失?

rust - 检索对树值的可变引用

rust - 介绍中的 Actix Web 示例给出运行时错误线程 'main' 在 'called ` Option::unwrap( )` on a ` None`value'

rust - 使用具有泛型类型的运算符时出错