在非阻塞模式下将 Trait 类型与 rust-portaudio 结合使用

2024-01-11

我正在关注正弦例子 https://github.com/RustAudio/rust-portaudio/blob/master/examples/sine.rs在 rust-portaudio 示例目录(使用非阻塞 API)中,我试图获取run()使用 Trait 类型参数而不是计算其中的样本run() itself.

我定义的特征非常简单:

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() https://github.com/RustAudio/rust-portaudio/blob/master/src/lib.rs#L472),这是我沮丧的主要原因......


In main,我可以创建一个Evaluatable输入并传递它就好了(旁白:我很惊讶这能起作用,在中做对象main get '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():

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()
}

现在,Rust 似乎有一个问题,即生命周期不存在'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...

  1. 为什么 Rust 能够让我使用SineGenerator from main(),但不让我使用Combine它采用相同的对象(我认为具有相同的生命周期)?
  2. 有没有更好的实现方法Combine这能让我在这里做我想做的事吗?我必须引用,因为 Trait 类型在编译时没有定义大小。

  1. 为什么 Rust 能够让我使用SineGenerator from main(),但不让我使用Combine它采用相同的对象(我认为具有相同的生命周期)?

A 'static绑定在类型参数上意味着该类型不能借用任何寿命短于'static. Your SineGenerator不借用任何东西,所以它尊重这个界限。Combine另一方面,不尊重边界,因为它包含借用的指针,并且您用比'static通过存储对局部变量的引用Combine object.

  1. 有没有更好的实现方法Combine这能让我在这里做我想做的事吗?我必须引用,因为 Trait 类型在编译时没有定义大小。

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

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拥有Evaluatables,它将尊重'static绑定(如果两者F and S are 'static他们自己)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在非阻塞模式下将 Trait 类型与 rust-portaudio 结合使用 的相关文章

随机推荐