我在理解Rust 的范围时遇到了问题.我try 实现一个简单的代码来播放声音.我想填充缓冲区然后播放它,但我无法让它编译.

我得到了这个方法:

fn main() {
    let channels: usize = 2;
    let device = initialize_device();
    let config = initialize_configuration(&device, channels as u16);

    let mut stream_buffer = [0.0 as f32; 64];
    {
        let mut oscillator = Oscillator::new(440.0 as f32, 0.0 as f32, 44100.0 as f32, &mut stream_buffer);

        let processor = move |_data: &mut [f32], _: &cpal::OutputCallbackInfo| {
            //FIXME: Send data from oscillator to _data
            oscillator.process();
        };
    
        let stream = build_outputstream(config, device, Box::new(processor));

        let _ = stream.play();

        std::thread::sleep(std::time::Duration::from_millis(2000));
    }
}

变量"stream_buffer"位于作用域之前

    let mut stream_buffer = [0.0 as f32; 64];
    {
        ...
    }

在那里执行其余代码.

根据我从rust文档中了解到的情况,默认情况下,变量位于堆栈上,我们可以将它们装箱以将它们放在堆上. 因此,stream_buffer位于堆栈上,并且应该保留在堆栈上直到程序结束.即使我没有手动创建它下面的范围.

该文档还表示,堆上的变量在超出范围时会自动销毁. 所以,我知道我的盒装processor的生命周期比stream_buffer短,并且它在其范围结束时被销毁.

 let mut stream_buffer = [0.0 as f32; 64];
    {
        let mut oscillator = Oscillator::new(440.0 as f32, 0.0 as f32, 44100.0 as f32, &mut stream_buffer);

        let processor = move |_data: &mut [f32], _: &cpal::OutputCallbackInfo| {
            //FIXME: Send data from oscillator to _data
            oscillator.process();
        };
    
        let stream = build_outputstream(config, device, Box::new(processor));
        ...
    }

但编译器抱怨"stream_buffer"不够活跃.

error[E0597]: `stream_buffer` does not live long enough
  --> src\main.rs:42:88
   |
40 |     let mut stream_buffer = [0.0 as f32; 64];
   |         ----------------- binding `stream_buffer` declared here
41 |     {
42 |         let mut oscillator = Oscillator::new(440.0 as f32, 0.0 as f32, 44100.0 as f32, &mut stream_buffer);
   |                                                                                        ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
49 |         let stream = build_outputstream(config, device, Box::new(processor));
   |                                                         ------------------- cast requires that `stream_buffer` is borrowed for `'static`
...
55 | }
   | - `stream_buffer` dropped here while still borrowed
   |
   = note: due to object lifetime defaults, `Box<dyn for<'a, 'b> FnMut(&'a mut [f32], &'b OutputCallbackInfo) + Send>` actually means `Box<(dyn for<'a, 'b> FnMut(&'a mut [f32], &'b OutputCallbackInfo) + Send + 'static)>`

如果我按照编译器建议的那样将stream_buffer设置为静态,它就会起作用.但我不想. 我想我明白,因为处理器必须在堆上,所以我别无 Select ,只能让stream_buffer保持静态?我不能把stream_buffer放在堆栈上,把处理器放在堆上吗?

推荐答案

以下是您问题的一个最小例子:

fn main() {
    let s = String::from("hello world");
    let clo = || {println!("{s}");};
    takes_boxed_fn(Box::new(clo));
    
}

fn takes_boxed_fn(_: Box<dyn Fn()>) {}

以及它产生的错误:

error[E0597]: `s` does not live long enough
 --> src/main.rs:3:30
  |
3 |     let clo = || {println!("{s}");};
  |               --             ^ borrowed value does not live long enough
  |               |
  |               value captured here
4 |     takes_boxed_fn(Box::new(clo));
  |                         ------------- cast requires that `s` is borrowed for `'static`
5 |     
6 | }
  | - `s` dropped here while still borrowed
  |
  = note: due to object lifetime defaults, `Box<dyn Fn()>` actually means `Box<(dyn Fn() + 'static)>`

有一个很好的注释来解释这个问题:

= note: due to object lifetime defaults, `Box<dyn Fn()>` actually means `Box<(dyn Fn() + 'static)>`

这意味着takes_boxed_fn的定义相当于:

fn takes_boxed_fn(_: Box<dyn Fn() + 'static>) {}

这要求您的关闭是静态的!幸运的是,这相对容易放松,只需度过明确的一生即可:

fn takes_boxed_fn<'a>(_: Box<dyn Fn() + 'a>) {}

Playground

Rust相关问答推荐

无法定义名为&new&的关联函数,该函数的第一个参数不是self

在rust sqlx中使用ilike和push bind

如何在Rust中缩短数组

什么时候使用FuturesOrdered?

在运行特定测试时,如何 suppress cargo test 的空输出?

类型生命周期绑定的目的是什么?

如何限制 GtkColumnView 行数

仅在使用 &mut 或线程时borrow 的数据在闭包之外转义?

为什么 Rust 字符串没有短字符串优化 (SSO)?

返回迭代器的特征

在构建器模式中捕获 &str 时如何使用生命周期?

在 Rust 中,将可变引用传递给函数的机制是什么?

为什么具有 Vec 变体的枚举没有内存开销?

没有分号的返回表达式的性能是否比使用返回更好?在Rust ?

如果我不想运行析构函数,如何移出具有析构函数的 struct ?

Rust HRTB 是相同的,但编译器说一种类型比另一种更通用

Abortable:悬而未决的期货?

为什么 Rust 标准库同时为 Thing 和 &Thing 实现特征?

list 中没有指定目标 - 必须存在 src/lib.rs、src/main.rs、[lib] 部分或 [[bin]] 部分

为什么我返回的 impl Trait 的生命周期限制在其输入的生命周期内?