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

时间:2018-12-08 18:45:19

标签: rust thread-safety closures channel lifetime

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

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实际上可以解决问题。我不知道为什么会这样。

Another question I've found解释了如何通过通道发送可变切片,但是我拥有不可变的切片,因此我认为比那里已经解释过的解决方案更简单。

要结束这一点:我知道可以重组代码来避免使用通道。但是,我仍然对该解决方案感兴趣,因此我可以自己解决频道和回调的未来问题。

1 个答案:

答案 0 :(得分:1)

它在我的大脑中发出咔嗒声。

此外,对于move关键字,还需要满足以下条件:

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

解决方案是从切片中创建一个拥有的对象,例如Vec。通过添加.to_vec()可以简单地做到这一点:

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

Vec可以自由传递,不会造成任何生命周期冲突。 :)