Help passing data out of a closure that takes a reference
โ Rust ๐ 2025-10-09 ๐ค surdeus ๐๏ธ 5Hi there! Relative rust newcomer here.
I'm trying to make use of a library (midir) that allows me to handle MIDI messages via a callback that I provide.
I can do something simple, like printing out the messages as they arrive, but to do something more complex (i.e. have a synth engine play those notes), I think I need to be able to pass the message outside of the callback. But I'm only given a reference to the data, and whenever I try to do that, I run into errors.
As an example, here's a modification of the library's test_read_input.rs example code illustrating what I was trying to do:
use std::error::Error;
use std::io::{stdin, stdout, Write};
use std::sync::mpsc;
use std::thread;
use midir::{Ignore, MidiInput};
fn main() {
match run() {
Ok(_) => (),
Err(err) => println!("Error: {}", err),
}
}
fn run() -> Result<(), Box<dyn Error>> {
let mut input = String::new();
let mut midi_in = MidiInput::new("midir reading input")?;
midi_in.ignore(Ignore::None);
// Get an input port (read from console if multiple are available)
let in_ports = midi_in.ports();
let in_port = match in_ports.len() {
0 => return Err("no input port found".into()),
1 => {
println!(
"Choosing the only available input port: {}",
midi_in.port_name(&in_ports[0]).unwrap()
);
&in_ports[0]
}
_ => {
println!("\nAvailable input ports:");
for (i, p) in in_ports.iter().enumerate() {
println!("{}: {}", i, midi_in.port_name(p).unwrap());
}
print!("Please select input port: ");
stdout().flush()?;
let mut input = String::new();
stdin().read_line(&mut input)?;
in_ports
.get(input.trim().parse::<usize>()?)
.ok_or("invalid input port selected")?
}
};
println!("\nOpening connection");
let in_port_name = midi_in.port_name(in_port)?;
let (tx, rx) = mpsc::channel(); // create a message channel
// _conn_in needs to be a named parameter, because it needs to be kept alive until the end of the scope
let _conn_in = midi_in.connect(
in_port,
"midir-read-input",
move |stamp, message, _| {
println!("{}: {:?} (len = {})", stamp, message, message.len());
tx.send((stamp, message)).unwrap(); // try to send the midi message down the channel, this fails
},
(),
)?;
thread::spawn(move || {
for msg in rx {
println!("received {msg:?}");
}
});
println!(
"Connection open, reading input from '{}' (press enter to exit) ...",
in_port_name
);
input.clear();
stdin().read_line(&mut input)?; // wait for next enter key press
println!("Closing connection");
Ok(())
}
and the error that this produces:
error[E0521]: borrowed data escapes outside of closure
--> examples/test_read_input_message_passing.rs:58:13
|
50 | let (tx, rx) = mpsc::channel(); // create a message channel
| -- `tx` declared here, outside of the closure body
...
56 | move |stamp, message, _| {
| ------- `message` is a reference that is only valid in the closure body
57 | println!("{}: {:?} (len = {})", stamp, message, message.len());
58 | tx.send((stamp, message)).unwrap(); // try to send the midi message down the channel...
| ^^^^^^^^^^^^^^^^^^^^^^^^^ `message` escapes the closure body here
|
= note: requirement occurs because of the type `std::sync::mpsc::Sender<(u64, &[u8])>`, which makes the generic argument `(u64, &[u8])` invariant
= note: the struct `std::sync::mpsc::Sender<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
For more information about this error, try `rustc --explain E0521`.
Could someone show me where I'm going wrong? I think I understand the idea behind the error (trying to use a reference outside where it is valid), but not how to fix it. I imagine this might be a relatively obvious answer to a more experienced Rust programmer, and I just haven't fully understood some concept yet.
(Cross-posting this from How to implement message queues using the callbacks? ยท Boddlnagg/midir ยท Discussion #172 ยท GitHub because I think this might be me not understanding a general rust concept)
2 posts - 2 participants
๐ท๏ธ Rust_feed