2017-09-17 1 views
2

Je suis le sine example dans le répertoire des exemples rust-portaudio (qui utilise l'API non bloquante), et j'essaie d'obtenir run() avec un trait tapez argument au lieu de calculer les échantillons dans run() lui-même.Utilisation des types de caractères avec port-rouille en mode non-bloquant

Le trait que je l'ai défini est assez simple:

pub trait Evaluatable { 
    fn evaluate(&mut self) -> (f32, f32); 
} 

J'ai changé la signature de la fonction run() à ce qui suit pour accepter mon trait:

fn run<E: Evaluatable + 'static>(mut generator: E) -> Result<(), pa::Error> 

et upated la fonction de rappel pour appeler le evaluate() sur le type de trait au lieu de générer lui-même des échantillons:

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 doit être 'static en raison de ce rappel (voir open_non_blocking_stream()), qui est la principale source de ma frustration ...


En main, je peux créer un type Evaluatable et passer en très bien (à part: Je suis surpris que cela fonctionne, les objets ne se main vie '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() 
} 

Mais je veux être en mesure de combiner des signaux, donc je fait une struct qui peut les combiner:

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

et a essayé de l'utiliser dans 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() 
} 

Maintenant, Rust semble avoir un problème avec la durée de vie ne pas être '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. Pourquoi wa s Rust en mesure de me permettre d'utiliser SineGenerator de main(), mais ne me laisse pas utiliser Combine qui prend les mêmes objets (avec, je suppose, les mêmes durées de vie)?
  2. Existe-t-il une meilleure façon de mettre en œuvre Combine qui me permettra de faire ce que je veux faire ici? J'ai dû prendre des références parce que les types de caractères n'ont pas de taille définie lors de la compilation.

Répondre

2
  1. Pourquoi était Rust en mesure de me permettre d'utiliser SineGenerator de main(), mais ne me laisse pas utiliser Combine qui prend les mêmes objets (avec, je suppose, les mêmes durées de vie)?

Un 'static lié sur un paramètre de type signifie que le type ne peut emprunter tout ce qui vit plus courte que 'static. Votre SineGenerator n'emprunte rien, donc il respecte cette limite.D'autre part, Combine ne respecte pas la limite car elle contient des pointeurs empruntés et vous l'instanciez avec une durée de vie inférieure à 'static en stockant des références aux variables locales dans l'objet Combine.

  1. Y at-il une meilleure façon de mettre en œuvre Combine qui me permettra de faire ce que je veux faire ici? J'ai dû prendre des références parce que les types de caractères n'ont pas de taille définie lors de la compilation.

La solution typique consiste à utiliser des paramètres de type au lieu d'objets 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() 
} 

En ayant Combine possèdent les Evaluatable s, il respectera la limite 'static (si les deux F et S sont eux-mêmes 'static).

+0

A travaillé impeccablement, merci! On dirait que j'ai encore beaucoup à apprendre avec Rust. – crs