Противоречивые требования времени жизни при пересылке фрагментов из статического обратного вызова в канал - PullRequest
0 голосов
/ 08 декабря 2018

Я использую библиотеку Rust Midi для получения и обработки сообщений 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 на самом деле делает свое дело.Я понятия не имею, почему это может быть.

Другой вопрос, который я нашел объясняет, как отправлять изменяемые фрагменты по каналам, но у меня есть неизменяемые фрагменты, поэтому я предполагаю, что есть более простое решениечем тот, который был объяснен там.

Чтобы закрыть это: я знаю, что можно реструктурировать код, чтобы избежать каналов.Тем не менее, я все еще заинтересован в решении, поэтому я могу решить будущие проблемы с каналами и обратными вызовами самостоятельно.

1 Ответ

0 голосов
/ 09 декабря 2018

Это щелкнуло в моем мозгу.

Кроме того, для ключевого слова move необходимо следующее:

connect предоставляет ссылку на массив, который живет для области видимостиобратный звонок.Это означает, что когда обратный вызов завершается, &[u8] становится недоступным.Я попытался отправить ссылку за пределы обратного вызова, что не имело смысла, потому что тогда ему пришлось бы жить дольше.

Решение состоит в том, чтобы создать собственный объект из среза, например Vec.Это просто сделать, добавив .to_vec():

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

Vec можно свободно обойти без каких-либо конфликтных ситуаций.:)

...