代码之家  ›  专栏  ›  技术社区  ›  adahn

“参数类型'C'可能寿命不够长”,如果不需要的话

  •  2
  • adahn  · 技术社区  · 6 年前

    我正在用Rust编写非常基本的AI系统。其主要部件有:

    • Action s、 可由图书馆用户实现,用于特定用途,
    • 通用的 Context ,它将传递给所有操作,并且只需要在操作执行期间活动,
    • ActionsContainer ,它“全局”存储所有可能的操作,
    • System ,它选择并运行正确的操作。有许多系统,每个代理一个。然而,他们有着相同的行为,所以他们都引用了一个共同的 操作容器

    这里有一个最简单的例子来说明我的问题。

    // Generic system
    
    trait Context {}
    
    trait Action<C: Context> {
        fn run(&self, context: &mut C);
    }
    
    struct ActionsContainer<C: Context> {
        actions: Vec<Box<Action<C>>>,
    }
    
    struct System<'a, C: Context> {
        actions: &'a ActionsContainer<C>,
    }
    
    impl<'a, C: Context> System<'a, C> {
        fn run(&self, c: &mut C) {
            self.actions.actions[0].run(c);
        }
    }
    
    // Implementation
    
    struct ContextImpl<'a> {
        x: &'a i32,
        y: i32,
    }
    
    impl<'a> Context for ContextImpl<'a> {}
    
    struct ActionImpl {}
    
    impl<'a> Action<ContextImpl<'a>> for ActionImpl {
        fn run(&self, c: &mut ContextImpl) {
            println!("Action!");
            c.y = c.x;
        }
    }
    
    // usage
    fn main() {
        let container = ActionsContainer {
            actions: vec![Box::new(ActionImpl {})],
        };
    
        {
            let system = System {
                actions: &container,
            };
    
            {
                let x = 8;
                let mut context = ContextImpl { x: &x, y: 0 };
    
                system.run(&context);
    
                assert_eq!(context.y, context.x)
            }
        }
    }
    

    playground

    编译器抱怨:

    error[E0309]: the parameter type `C` may not live long enough
      --> src/main.rs:14:5
       |
    13 | struct System<'a, C: Context> {
       |                   -- help: consider adding an explicit lifetime bound `C: 'a`...
    14 |     actions: &'a ActionsContainer<C>,
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       |
    note: ...so that the reference type `&'a ActionsContainer<C>` does not outlive the data it points at
      --> src/main.rs:14:5
       |
    14 |     actions: &'a ActionsContainer<C>,
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    然而 C 未存储在中 行动 。它只需要活一会儿 run 正在执行。另一方面 行动 需要和整个人一样长寿吗 系统 。有什么方法可以注释这个吗?

    我怀疑,这与更高的等级特质界限有关,但我不知道如何在这里使用它们。

    我也试着摆脱 行动 作为特征对象,只需使用普通函数引用:

    type Action<C> = fn(&mut C);
    
    struct ActionsContainer<C: Context> {
        actions: Vec<&'static Action<C>>,
    }
    

    但是编译器的错误几乎是一样的。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Shepmaster Lukas Kalbertodt    6 年前

    我找到了解决方案:

    // Generic system
    
    trait Context {}
    
    trait Action<C: Context> {
        fn run(&self, context: &mut C);
    }
    
    struct ActionsContainer<A> {
        actions: Vec<Box<A>>,
    }
    
    struct System<'a, A: 'a> {
        actions: &'a ActionsContainer<A>,
    }
    
    impl<'a, A> System<'a, A> {
        fn run<C>(&self, c: &mut C)
        where
            C: Context,
            A: Action<C>,
        {
            self.actions.actions[0].run(c);
        }
    }
    
    // Implementation
    
    struct ContextImpl<'a> {
        x: &'a i32,
        y: i32,
    }
    
    impl<'a> Context for ContextImpl<'a> {}
    
    struct ActionImpl {}
    
    impl<'a> Action<ContextImpl<'a>> for ActionImpl {
        fn run(&self, c: &mut ContextImpl) {
            println!("Action!");
            c.y = *c.x;
        }
    }
    
    // usage
    fn main() {
        let container = ActionsContainer {
            actions: vec![Box::new(ActionImpl {})],
        };
    
        {
            let system = System {
                actions: &container,
            };
    
            {
                let x = 8;
                let mut context = ContextImpl { x: &x, y: 0 };
    
                system.run(&mut context);
    
                assert_eq!(context.y, *context.x)
            }
        }
    }
    

    Playground

    Rust总是假设泛型结构中提到的特性将存储在该结构中(因此我的终身问题)。如果您不打算存储特征,请不要在结构定义中提及它。相反,使用更一般的边界,并在定义适当生存期的方法上对其进行澄清。