rust - 精明的一生理解移动关键字

标签 rust

我一直在通过 Rust 和 Rust 库使用 AudioUnit coreaudio-rs .他们的例子似乎运作良好:

extern crate coreaudio;

use coreaudio::audio_unit::{AudioUnit, IOType};
use coreaudio::audio_unit::render_callback::{self, data};
use std::f32::consts::PI;


struct Iter {
    value: f32,
}
impl Iterator for Iter {
    type Item = [f32; 2];
    fn next(&mut self) -> Option<[f32; 2]> {
        self.value += 440.0 / 44_100.0;
        let amp = (self.value * PI * 2.0).sin() as f32 * 0.15;
        Some([amp, amp])
    }
}


fn main() {
    run().unwrap()
}

fn run() -> Result<(), coreaudio::Error> {
    // 440hz sine wave generator.

    let mut samples = Iter { value: 0.0 };
    //let buf: Vec<[f32; 2]> = vec![[0.0, 0.0]];
    //let mut samples = buf.iter();

    // Construct an Output audio unit that delivers audio to the default output device.
    let mut audio_unit = try!(AudioUnit::new(IOType::DefaultOutput));

    // Q: What is this type?
    let callback = move |args| {
        let Args { num_frames, mut data, .. } = args;
        for i in 0..num_frames {
            let sample = samples.next().unwrap();
            for (channel_idx, channel) in data.channels_mut().enumerate() {
                channel[i] = sample[channel_idx];
            }
        }
        Ok(())
    };

    type Args = render_callback::Args<data::NonInterleaved<f32>>;
    try!(audio_unit.set_render_callback(callback));
    try!(audio_unit.start());

    std::thread::sleep(std::time::Duration::from_millis(30000));

    Ok(())
}

但是,将其稍微更改为通过缓冲区加载也不起作用:

extern crate coreaudio;

use coreaudio::audio_unit::{AudioUnit, IOType};
use coreaudio::audio_unit::render_callback::{self, data};

fn main() {
    run().unwrap()
}

fn run() -> Result<(), coreaudio::Error> {
    let buf: Vec<[f32; 2]> = vec![[0.0, 0.0]];
    let mut samples = buf.iter();

    // Construct an Output audio unit that delivers audio to the default output device.
    let mut audio_unit = try!(AudioUnit::new(IOType::DefaultOutput));

    // Q: What is this type?
    let callback = move |args| {
        let Args { num_frames, mut data, .. } = args;
        for i in 0..num_frames {
            let sample = samples.next().unwrap();
            for (channel_idx, channel) in data.channels_mut().enumerate() {
                channel[i] = sample[channel_idx];
            }
        }
        Ok(())
    };

    type Args = render_callback::Args<data::NonInterleaved<f32>>;
    try!(audio_unit.set_render_callback(callback));
    try!(audio_unit.start());

    std::thread::sleep(std::time::Duration::from_millis(30000));

    Ok(())
}

它正确地说,buf 只存在到 run 结束并且没有足够长的时间供音频单元使用——这是有道理的,因为“借来的值必须在静态生命周期内有效...”。 无论如何,这不会打扰我;我可以修改迭代器以从缓冲区加载和读取就好了。但是,它确实提出了一些问题:

  1. 为什么 Iter { value: 0.0 }'static 生命周期?
  2. 如果它没有'static 生命周期,为什么说借用的值必须在'static 生命周期内有效?
  3. 如果它确实有 'static 生命周期,为什么?看起来它会在堆上并由 callback 关闭。
  4. 我知道 move 关键字允许在闭包内移动,这无助于我理解为什么它与生命周期交互。为什么它不能移动缓冲区?我是否必须将缓冲区和迭代器都移动到闭包中?我该怎么做?
  5. 综上所述,我如何在不尝试自己成为编译器的情况下计算出预期的生命周期?猜测和编译似乎并不总是解决这些问题的直接方法。

最佳答案

Why does the Iter { value: 0.0 } have the 'static lifetime?

它没有;只有引用有生命周期。

why does it say the borrowed value must be valid for the 'static lifetime

how do I figure out the expected lifetime without trying to be a compiler myself

阅读文档;它告诉你限制:

fn set_render_callback<F, D>(&mut self, f: F) -> Result<(), Error> 
where
    F: FnMut(Args<D>) -> Result<(), ()> + 'static, // <====
    D: Data

此限制意味着 F 内的任何引用必须至少与 'static 生命周期一样长。没有引用文献也是可以接受的。

所有类型和生命周期限制都在函数边界表示——这是 Rust 的硬性规则。

I understand that the move keyword allows moving inside the closure, which doesn't help me understand why it interacts with lifetimes.

move 关键字所做的唯一一件事就是强制将闭包中直接使用 的每个变量移动到闭包中。否则,编译器会尝试保守并根据闭包内的用法移入引用/可变引用/值。

Why can't it move the buffer?

变量 buf 永远不会在闭包内部使用。

Do I have to move both the buffer and the iterator into the closure? How would I do that?

通过在闭包内创建迭代器。现在 buf 被用在闭包内部并且将被移动:

let callback = move |args| {
    let mut samples = buf.iter();
    // ...
}

It doesn't seem like guessing and compiling is always a straightforward method to resolving these issues.

有时是这样,有时您必须考虑为什么您认为代码是正确的以及为什么编译器声明它不是正确的,并达成共识。

关于rust - 精明的一生理解移动关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44080917/

相关文章:

rust - 将 actix_web 响应的主体提取到字符串中的正确方法是什么?

naming - 为什么叫它 "Rust"?

events - 是否可以注册在创建结构之前/之后发生的事件?

rust - 多个非返回函数调用中只有一部分与async/await同时运行

string - 如何从整数转换为字符串?

syntax - 奇怪的语法错误 'error: expected one of ` ,` or ` :`, found ` else`'

rust - `flat_map` 如何影响我的代码?

alias - Rust 中的类型别名

rust - 为什么不能在同一结构中存储值和对该值的引用?

rust - 如何使用 StructOpt 将参数解析为 Vec 而不将其视为多个参数?