我一直在玩Rust的AudioUnit和Rust库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
的结尾,而且音频单元的寿命不够 - 这是有意义的,因为“借用的值必须对于静态寿命......“
在任何情况下,这都不会打扰我;我可以修改迭代器来加载和从缓冲区读取就好了。但是,它确实提出了一些问题:
Iter { value: 0.0 }
的生命期为'static
?'static
生命周期,为什么说借用的值必须在'static
生命周期内有效?'static
生命周期,为什么?好像它会在堆上并由callback
关闭。move
关键字允许在闭包内移动,这无助于我理解为什么它与生命周期相互作用。为什么不能移动缓冲区?我是否必须将缓冲区和迭代器都移动到闭包中?我该怎么做?答案 0 :(得分:3)
为什么
Iter { value: 0.0 }
的生命周期为'static
?
没有;只有参考文献有生命周期。
为什么说借来的值必须对
有效'static
有效期如何在不尝试成为编译器的情况下找出预期的生命周期
阅读文档;它告诉你限制:
fn set_render_callback<F, D>(&mut self, f: F) -> Result<(), Error>
where
F: FnMut(Args<D>) -> Result<(), ()> + 'static, // <====
D: Data
此限制意味着F
内的任何引用必须至少与'static
生命周期一样长。没有参考也是可以接受的。
所有类型和生命周期限制都在函数边界表示 - 这是Rust的一项硬性规则。
我理解
move
关键字允许在闭包内部移动,这无助于我理解为什么它与生命周期交互。
move
关键字唯一能做的就是强制将闭包中的每个变量直接使用移动到闭包中。否则,编译器会尝试保守,并根据闭包内的用法移动引用/可变引用/值。
为什么不能移动缓冲区?
变量buf
永远不会在闭包内使用。
我是否必须将缓冲区和迭代器都移动到闭包中?我该怎么做?
通过在闭包内创建迭代器。现在buf
在闭包内使用并将被移动:
let callback = move |args| {
let mut samples = buf.iter();
// ...
}
似乎猜测和编译并不总是解决这些问题的直接方法。
有时它是,有时你必须考虑为什么你认为代码是正确的以及为什么编译器说它不是并且理解。