在非阻塞模式下使用带有rust-portaudio的Trait类型

时间:2017-09-17 02:49:39

标签: rust

我跟随在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
  1. 为什么Rust能够允许我使用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()使用相同的对象(我假设,相同的生命周期)?
  2. 有没有更好的方法来实现Combine,这将允许我做我想做的事情?我必须参考,因为Trait类型在编译时没有定义大小。

1 个答案:

答案 0 :(得分:2)

  
      
  1. 为什么Rust能够允许我使用SineGenerator中的main(),但不会让我使用Combine来获取相同的对象(我假设,相同的生命周期) )?
  2.   

对类型参数绑定的'static意味着该类型可能不会借用短于'static的任何内容。你的SineGenerator没有借用任何东西,所以它尊重那个界限。另一方面,Combine不尊重绑定,因为它包含借用的指针,并且通过在{{1中存储对局部变量的引用来实例化它的生命周期短于'static。对象。

  
      
  1. 有没有更好的方法来实现Combine,这将允许我做我想做的事情?我不得不接受引用,因为Trait类型在编译时没有定义大小。
  2.   

典型的解决方案是使用类型参数而不是特征对象。

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界限(如果'staticF都是S )。