我跟随在rust-portaudio示例目录中的sine example(使用非阻塞API),并且我试图让run()
使用特征键入参数而不是计算run()
本身内的样本。
我定义的特征非常简单:
pub trait Evaluatable {
fn evaluate(&mut self) -> (f32, f32);
}
我将run()
函数签名更改为以下内容以接受我的特征:
fn run<E: Evaluatable + 'static>(mut generator: E) -> Result<(), pa::Error>
并更新回调函数以在特征类型上调用evaluate()
而不是自己生成样本:
let callback = move |pa::OutputStreamCallbackArgs { buffer, frames, .. }| {
let mut idx = 0;
for _ in 0..frames {
let samples = generator.evaluate();
buffer[idx] = samples.0;
buffer[idx+1] = samples.1;
idx += 2;
}
pa::Continue
};
E
由于此回调而必须为'static
(请参阅open_non_blocking_stream()
),这是我沮丧的主要原因......
在main
中,我可以创建一个Evaluatable
类型并将其传递到正确的位置(除此之外:我很惊讶这是有效的,在main
中执行对象获取{{1终身?):
'static
但我希望能够组合信号,所以我制作了一个可以组合它们的结构:
fn main() {
// Implements Evaluatable
// arguments are: sample rate, frequency, amplitude
let mut sine_generator = SineGenerator::new(44100.0, 200.0, 0.3);
run(sine_generator).unwrap()
}
并尝试在use evaluatable::Evaluatable;
pub struct Combine<'a> {
first: &'a mut (Evaluatable + 'a),
second: &'a mut (Evaluatable + 'a),
}
impl<'a> Combine<'a> {
pub fn new(first: &'a mut Evaluatable, second: &'a mut Evaluatable) -> Combine<'a> {
Combine {first, second}
}
}
impl<'a> Evaluatable for Combine<'a> {
fn evaluate(&mut self) -> (f32, f32) {
let first_output = self.first.evaluate();
let second_output = self.second.evaluate();
(first_output.0 + second_output.0, first_output.1 + second_output.1)
}
}
中使用它:
main()
现在,Rust似乎有一个问题,生命不是fn main() {
let mut sine_generator1 = SineGenerator::new(44100.0, 200.0, 0.3);
let mut sine_generator2 = SineGenerator::new(44100.0, 250.0, 0.3);
let combine = Combine::new(&mut sine_generator1, &mut sine_generator2);
run(combine).unwrap()
}
:
'static
Error[E0597]: `sine_generator1` does not live long enough
--> src/main.rs:27:37
|
27 | let combine = Combine::new(&mut sine_generator1, &mut sine_generator2);
| ^^^^^^^^^^^^^^^ does not live long enough
28 | run(combine).unwrap()
29 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
中的SineGenerator
,但我不会让main()
使用相同的对象(我假设,相同的生命周期)?Combine
,这将允许我做我想做的事情?我必须参考,因为Trait类型在编译时没有定义大小。答案 0 :(得分:2)
- 为什么Rust能够允许我使用
醇>SineGenerator
中的main()
,但不会让我使用Combine
来获取相同的对象(我假设,相同的生命周期) )?
对类型参数绑定的'static
意味着该类型可能不会借用短于'static
的任何内容。你的SineGenerator
没有借用任何东西,所以它尊重那个界限。另一方面,Combine
不尊重绑定,因为它包含借用的指针,并且通过在{{1中存储对局部变量的引用来实例化它的生命周期短于'static
。对象。
- 有没有更好的方法来实现
醇>Combine
,这将允许我做我想做的事情?我不得不接受引用,因为Trait类型在编译时没有定义大小。
典型的解决方案是使用类型参数而不是特征对象。
Combine
让pub struct Combine<F, S>
where
F: Evaluatable,
S: Evaluatable,
{
first: F,
second: S,
}
fn main() {
let sine_generator1 = SineGenerator::new(44100.0, 200.0, 0.3);
let sine_generator2 = SineGenerator::new(44100.0, 250.0, 0.3);
let combine = Combine::new(sine_generator1, sine_generator2);
run(combine).unwrap()
}
拥有Combine
s,它会尊重Evaluatable
界限(如果'static
和F
都是S
)。