1

I have a trait that genericizes getting a (audio, etc) sample from a "signal":

pub trait Signal {
    /// When requested, all signals must produce a f64 sample.
    fn evaluate(&mut self) -> f64;
}

I wanted to implement this trait for plain-old f64s and make it just keep on returning the same value instead of making a whole different struct that implements Signal to do the same thing:

impl Signal for f64 {
    fn evaluate(&mut self) -> f64 {
        *self
    }
}

It turns out that this doesn't matter anyway; even if I make said struct, when I try to give a default value it doesn't work either way.


In one of my signal generators, I'd like to switch over from using a f64 type:

// Sine implements Signal
pub struct Sine {
    frequency: f64,
    // Other fields omitted
}

To a Signal type, to be able to have the frequency change over time:

pub struct Sine<F> where
    F: Signal,
{
    frequency: F,
    // Other fields omitted
}

The problem arises when I go to make a Sine::new() function that tries to default the parameterized type (NOTE that I needed to use parameterized types to capture a trait type instead of using references due to a previous issue with borrowing I had with rust-portaudio):

impl<F> Sine<F> where
    F: Signal,
{
    /// Creates a new Sine wave signal generator.
    pub fn new() -> Sine<F> {
        Sine {
            frequency: 444.0,
            // Other fields omitted
        }
    }
}

I get the following error:

error[E0308]: mismatched types
  --> src/dsp/generators/sine.rs:35:24
   |
35 |             frequency: 444.0,
   |                        ^^^^^ expected type parameter, found floating-point variable
   |
   = note: expected type `F`
              found type `{float}`

This same struct definition works fine as long as I have a new() where you explicitly pass in a type that implements Signal:

let sine_gen1 = generators::Sine::new(440.0);

but I would like to be able to default values instead of passing all of the arguments all of the time.

A few other things I've tried:

  • 444.0 as F
    • error[E0605]: non-primitive cast: 'f64' as 'F' (error[E0605]: non-primitive cast: 'f64' as 'F')
  • 440.0_f64 as Signal
    • error[E0620]: cast to unsized type: 'f64' as 'dsp::traits::Signal'
  • Making a new struct (called Constant) that takes in a f64 in its own new() function and implements Signal, then making an instance of that struct in Sine::new() and trying to set it to frequency
    • I haven't found a combination of doing this that seems to work, plus it kind of feels too hacky to be correct.
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
crs
  • 77
  • 1
  • 8
  • 1
    You cannot allow the caller of your function to provide a type `F` and then ignore it and return a `f64` instead. You'll want something like https://play.rust-lang.org/?gist=b9b137cfe0ef79791dedb6cbadc3c05c&version=stable – Shepmaster Sep 20 '17 at 19:01
  • I'm trying to be able to not provide any argument at all, but i want to create a default "Signal" trait (via an f64) for it to use in the struct. – crs Sep 20 '17 at 19:03
  • 1
    Did you see the examples in the linked duplicates, or the playground that I edited into my first comment? – Shepmaster Sep 20 '17 at 19:09
  • Oops, nope - walked away from my computer and saw it on mobile. I'll take a gander in a few minutes – crs Sep 20 '17 at 19:12
  • 1
    From the other question: "For whatever T the caller chooses, I will create a Foo with that type" -- Aaaahhhh! Ok. That makes complete sense. Don't try to make your constructor take in a generic type and then not even use it -- just tell the compiler you're going to use `f64s` there. Thanks! – crs Sep 20 '17 at 19:24

0 Answers0