Rust 变量如何在闭包中可变地使用而不被永久移动?

问题描述 投票:0回答:1

我正在编写一个简单的 Rust 程序,它将足够响亮的音频输入传输到输出设备。

我通过使用ringbuf获得输入和输出回调来共享状态,其方式深受此代码的启发。

但是,当我尝试在函数中使用我的结构之一的可变引用时,我遇到了此错误:

error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
   --> src/main.rs:72:25
    |
72  | ...et input_data_fn = move |data: &[f32], _: &cpal::InputCallbackInfo| {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `FnMut`
...
77  | ...   clipper.ingest(Chunk::new(samples, input_sample_rate));
    |       ------- closure is `FnOnce` because it moves the variable `clipper` out of its environment
...
124 | ...et input_stream = input.build_input_stream(&config, input_data_fn, err_f...
    |                            ------------------          ------------- the requirement to implement `FnMut` derives from here
    |                            |
    |                            required by a bound introduced by this call
    |
note: required by a bound in `build_input_stream`
   --> C:\Users\info\.cargo\registry\src\index.crates.io-6f17d22bba15001f\cpal-0.15.3\src\traits.rs:134:12
    |
125 |     fn build_input_stream<T, D, E>(
    |        ------------------ required by a bound in this associated function
...
134 |         D: FnMut(&[T], &InputCallbackInfo) + Send + 'static,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `DeviceTrait::build_input_stream`

我想不出解决办法,但想必编写

ringbuf
库的人找到了这个问题的解决方案。我注意到被调用的 函数包含一个 unsafe
 块,但我相信这更多地与边界检查有关,而不是所有权。

这是相关代码(如果有人感兴趣,还有

整个文件):

let mut sin_osc = SineOscillator::new(SIN_OSC_AMP, SIN_OSC_FREQ, output_sample_rate); let mut clipper = LoudClipCollector::new(IN_TRIGGER_ADB, MIN_CLIP_SECS, output_sample_rate); let input_data_fn = move |data: &[f32], _: &cpal::InputCallbackInfo| { let mut output_fell_behind = false; let mut samples: Vec<f32> = vec![]; samples.clone_from_slice(data); clipper.ingest(Chunk::new(samples, input_sample_rate)); match clipper.next() { Some(samples) => { for sample in samples { if producer.try_push(sample).is_err() { output_fell_behind = true; } } }, None => { for i in 0..data.len() { if producer.try_push(sin_osc.next().unwrap()).is_err() { output_fell_behind = true; } } }, }; if output_fell_behind { eprintln!("output stream fell behind: try increasing latency"); } };
    
rust ownership
1个回答
0
投票
原来答案就在

try_push

的签名里

fn try_push(&mut self, elem: Self::Item) -> Result<(), Self::Item> {
它使用 

&mut

——可变引用。

我的代码无法编译的原因是我在没有任何引用的情况下使用了

mut

,表示移动而不是借用。

pub fn ingest(mut self, chunk: Chunk) {
解决办法是添加一个字符

pub fn ingest(&mut self, chunk: Chunk) {


我将留下这个问题并回答,以防对其他人有用。我们非常欢迎任何具有更多 Rust 专业知识的人来扩展这个答案。

© www.soinside.com 2019 - 2024. All rights reserved.