如何正确引用相同的代码作为依赖项的依赖项?

How to properly reference the same code as a dependency of a dependency?

我有一个玩具项目正在使用 Amethyst game engine. I'm trying to write my own System for collecting user input, similar to the FlyMovementSystem and ArcBallRotationSystem they have implemented here

看来收集鼠标移动的正确方法是通过 EventChannel<Event>,其中 Event 来自 winit 板条箱,Amethyst 依赖于它,但并不依赖它-出口。

引用与 Amethyst 相同的 winit::Event 的 "right" 方法是什么?

这个问题目前没有很好的解决方案。最好的解决方法是添加对相同版本传递依赖的直接依赖:

[dependencies]
foo = "0.1" 
bar = "0.2" # `foo` depends on bar 0.2 and we need to keep these in sync

您可以使用 cargo tree 等工具 手动 确定 foo 所需的版本并使您的 Cargo.toml 保持最新。我强烈建议添加一条评论,说明您选择特定版本的原因。

如果 crate 在不同时使用底层依赖项的情况下很难使用,我也鼓励您向父 crate 提出问题,请求他们重新导出所需的内容。 Tokio crate 就是一个很好的例子,re-exports large chunks of the futures crate


与您的想法相似,I proposed having a way to use the same version as a dependency. Instead, the Cargo team opted to add the distinction of public and private dependencies。虽然从工程的角度来看这将是一个更好的解决方案,但在实施方面进展甚微。

另请参阅:

我将@Shepmaster 的回答保留为已接受的回答,因为它回答了我要问的一般问题。但多亏了@trentcl 的温和推动,以防万一有人发现这个问题是因为它与 Amethyst 的关系,这就是我最终做的事情。

根本不要尝试获得 winit::Events

当您将 InputBundle<AX, AC> 附加到您的 GameData 时,它会设置一个 InputSystem<AX, AC>,以 InputEvent<AC> 的形式重新发布 winit::Events

它通过将 EventChannel<InputEvent<AC>> 设置为资源来实现此目的,您可以通过 ECS 系统中的 Read 类型访问它。解释了 EventChannels 及其用法 in the Amethyst Book

我后来改用另一种方法来处理我的用户输入,但大致是这样的(注意:Amethyst a little after v0.10.0):

pub struct MouseMovementSystem {
    reader: Option<ReaderId<InputEvent<()>>>, // AC = () 
}

impl<'s> System<'s> for MouseMovementSystem {
    type SystemData = (
        Read<'s, EventChannel<InputEvent<()>>>,
        /* and others */
    }

    fn run(&mut self, (events, /* and others */): Self::SystemData) {
        let foo = events.read(self.reader.as_mut().unwrap())
            .yadda_yadda(/* ... */); // event processing logic
        do_stuff(foo);
    }

    fn setup(&mut self, res: &mut Resources) {
        use amethyst::core::specs::prelude::SystemData;
        Self::SystemData::setup(res);
        self.reader = Some(res.fetch_mut::<EventChannel<InputEvent<()>>>().register_reader());
    }
}