将切片从静态回调转发到通道时的生存期要求冲突



我正在使用 Rust Midi 库来接收和处理实时 Midi 消息。它公开了一个connect函数,该函数接受一个回调,该回调将为到达的每个 Midi 消息调用。我的计划是将这些 Midi 消息转发到一个频道。这是代码的最小版本,仍然重现我的问题(Rust Playground 链接):

use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::sync_channel(0);
// The callback forwards all data it gets to the channel
connect(|data| tx.send(data).unwrap());
// `rx` will be given to some other part of the program here
}
// This is basically the function signature of my Midi library's `connect` function
// I *don't have control over it*, as it's part of that external library
fn connect<F>(callback: F)
where F: FnMut(&[u8]) + Send + 'static {}

在研究了这个问题一段时间后,我认为解决方案是在回调中添加move关键字。这对我来说是有道理的,因为回调可能比主函数存在的时间更长,因此当回调仍然需要它时tx可能已被丢弃。move强制回调按值捕获其环境,这应该导致tx与回调一样长。
然而,move什么也没改变;错误消息保持不变。

我注意到,当我将回调的参数从&[u8]更改为仅u8时,move实际上可以解决问题。我不知道为什么会这样。

我发现的另一个问题解释了如何通过通道发送可变切片,但我有不可变切片,所以我认为有一个比那里解释的解决方案更简单的解决方案。

关闭它:我知道可以重组代码以避免通道。但是,我仍然对解决方案感兴趣,因此我可以自己解决将来的频道和回调问题。

它在我的大脑中点击。

此外,对于move关键字,还需要以下内容:

connect提供对数组的引用,该数组存在于回调范围内。这意味着当回调完成时,&[u8]将无法访问。我尝试在回调之外发送引用,这毫无意义,因为那样它必须活得更长。

解决方案是从切片创建一个拥有的对象,例如Vec.通过添加.to_vec()来完成

connect(move |data| tx.send(data.to_vec()).unwrap());

Vec可以自由传递,没有任何终身冲突。 :)

最新更新