简体   繁体   English

为什么实现一个特征会改变生命周期的行为?

[英]Why does implementing a trait change the behaviour of lifetimes?

This is the smallest thing I could get that reproduces my problem:这是我能得到的最小的东西,它重现了我的问题:

pub trait IoEventHandling {
fn add_key_callback(&mut self, callback : Box<dyn FnMut(&[KeyActionState])>);
}

pub struct KeyActionState;

type KeyEvent<'io> = Box<dyn FnMut(&[KeyActionState]) + 'io>;

struct Window<'io> {
    key_callbacks: Vec<KeyEvent<'io>>,
}

// impl<'io> Window<'io> {
impl<'io> IoEventHandling for  Window<'io> {
    fn add_key_callback(&mut self, callback: KeyEvent<'io>) {
        self.key_callbacks.push(callback);
    }
}

struct PeripheralBureau<'io> {
    window: Window<'io>,
}

impl<'io> PeripheralBureau<'io> {
    fn window(&mut self) -> &mut Window<'io> {
        &mut self.window
    }
}

struct ECStorage;

impl ECStorage {
    fn component_query<T>(&mut self) -> impl Iterator<Item = ()> {
        std::iter::empty()
    }
}

struct KeyBoardMotion;

fn move_user_controlled_entities<'io>(
    ecs: &'io mut ECStorage,
    io_context: &mut PeripheralBureau<'io>,
) {
    io_context
        .window()
        .add_key_callback(Box::new(move |states| {
            for motion in ecs.component_query::<KeyBoardMotion>() {}
        }))
}

If you comment out impl<'io> IoEventHandling for Window<'io> { and uncomment the line above it it will work.如果您注释掉impl<'io> IoEventHandling for Window<'io> {并取消注释上面的行,它将起作用。

Why is implementing the trait breaking the code?为什么实现特征会破坏代码?

Your trait has a more strict requirement than the implementation.你的 trait 比实现有更严格的要求。 Namely, it requires callback to be Box<dyn FnMut(&[KeyActionState])> , which is (implicitly) Box<dyn FnMut(&[KeyActionState]) + 'static> ;即,它需要callbackBox<dyn FnMut(&[KeyActionState])> ,即(隐式) Box<dyn FnMut(&[KeyActionState]) + 'static> and therefore, when you call the trait method, you're required to satisfy this 'static bound - in other words, you're required to provide callback which can be held alive by the implementor indefinitely long.因此,当您调用 trait 方法时,您需要满足这个'static界限”——换句话说,您需要提供可以由实现者无限期保持活动状态的回调。

When implementing add_key_callback as an inherent method, however, you're lifting this restriction be making it dependent on the struct's lifetime - therefore, callback must simply outlive the struct.但是,当将add_key_callback实现为固有方法时,您将解除此限制,使其依赖于结构的生命周期 - 因此,回调必须简单地超过结构。

To make this work with the trait, you have to make the trait itself generic, so that each Window<'io> for different lifetime gets essentially its own impl<'io> IoEventHandling<'io> , and these implementations will require different lifetimes on the argument, therefore avoiding constraining it too hard.为了使这个特性与特性一起工作,你必须使特性本身通用,以便不同生命周期的每个Window<'io>基本上都有自己的impl<'io> IoEventHandling<'io> ,这些实现将需要不同的生命周期论点,因此避免过分约束它。

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

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