如何将动态分配与以迭代器作为参数的方法一起使用? [英] How to use dynamic dispatch with a method which takes an iterator as a parameter?

查看:71
本文介绍了如何将动态分配与以迭代器作为参数的方法一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个用于生锈的命令行应用程序,用于处理来自传感器的音频.我希望用户能够从多个选项中选择要应用的算法或过滤器.我希望使用动态调度来切换出一个在运行时实现我的过滤器特征的结构.但是,编译器不允许这样做,因为其中一种trait方法采用通用参数.

I am writing a command line application in rust for processing audio from a sensor. I would like the user to be able to choose an algorithm or filter to apply from several options. I was hoping to use dynamic dispatch to switch out a struct which implements my filter trait at runtime. However, this is not allowed by the compiler, because one of the trait methods takes a generic parameter.

如何在不引起任何编译器麻烦的情况下实现相同的功能?我知道一个简单的解决方案是将process方法的参数更改为数组或向量,但这是我的不得已的方法,因为我更喜欢采用Iterator或IntoIterator,因为它更通用,更适合我的具体需求.

How could I implement this same functionality, without causing any compiler troubles? I know that an easy solution is to change the parameter of the process method to an array or a vector, but this is my last resort, as I would much prefer to take an iterator or an IntoIterator, as it is more general, and suits my specific needs.

这是一些说明问题的代码.

Here is some code which demonstrates the problem.

trait SensorFilter {
    fn process(&self, sig: &mut impl Iterator<Item = f32>) -> Vec<f32>;
}

struct Alg1 {
    mul: f32,
}

struct Alg2 {
    add: f32,
}

impl SensorFilter for Alg1 {
    fn process(&self, sig: &mut impl Iterator<Item = f32>) -> Vec<f32> {
        sig.map(|x| x * self.mul).collect()
    }
}

impl SensorFilter for Alg2 {
    fn process(&self, sig: &mut impl Iterator<Item = f32>) -> Vec<f32> {
        sig.map(|x| x * self.add).collect()
    }
}

enum AlgChoice {
    Alg1,
    Alg2
}

fn main() {
    let choice = AlgChoice::Alg1; // user chooses via command-line.
    let mut sig = vec![0.,1.,2.,3.,4.,5.,6.].into_iter(); // iterator gets data from sensor.

    // This doesn't work, because my trait cannot be made into an object.
    let alg: &dyn SensorFilter = match choice {
        AlgChoice::Alg1 => Alg1{mul:0.3},
        _ => Alg2{add:1.2},
    };

    let result = alg.process(&mut sig);
    println!("{:?}",result);
}

谢谢:)

推荐答案

此处的窍门是将您的泛型函数参数更改为泛型特征参数:

The trick here is to change your generic function parameter to a generic trait parameter:

// Make the generic param into a type argument w/ constraints
trait SensorFilter<I> where I: Iterator<Item = f32> {
    fn process(&self, sig: &mut I) -> Vec<f32>;
}

struct Alg1 {
    mul: f32,
}

struct Alg2 {
    add: f32,
}

// Implement trait for all I that match the iterator constraint
impl<I: Iterator<Item = f32>> SensorFilter<I> for Alg1 {
    fn process(&self, sig: &mut I) -> Vec<f32> {
        sig.map(|x| x * self.mul).collect()
    }
}

impl<I: Iterator<Item = f32>> SensorFilter<I> for Alg2 {
    fn process(&self, sig: &mut I) -> Vec<f32> {
        sig.map(|x| x * self.add).collect()
    }
}

enum AlgChoice {
    Alg1,
    Alg2
}

fn main() {
    let choice = AlgChoice::Alg1; // user chooses via command-line.
    let mut sig = vec![0.,1.,2.,3.,4.,5.,6.].into_iter(); // iterator gets data from sensor.

    // Specify the type argument of your trait.
    let alg: &dyn SensorFilter<std::vec::IntoIter<f32>> = match choice {
        AlgChoice::Alg1 => &Alg1{mul:0.3},
        _ => &Alg2{add:1.2}, 
    };

    let result = alg.process(&mut sig);
    println!("{:?}",result);
}

这篇关于如何将动态分配与以迭代器作为参数的方法一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆