1

What I am trying to do is to implement a strategy pattern in Rust. In this example I have several sorting algos that I've coded:

use std::cmp::{ Ord, Ordering };

pub trait Sorter {
    fn sort<T>(arr: &mut Vec<T>, desc: bool) where T: Ord + Copy;
}

pub struct BubleSort;
pub struct SelectionSort;

impl Sorter for BubleSort {
    fn sort<T>(arr: &mut Vec<T>, desc: bool) where T: Ord + Copy{
        ...
    }
} 

impl Sorter for SelectionSort {
    fn sort<T>(arr: &mut Vec<T>, desc: bool) where T: Ord + Copy{
       ...
    }
}

Then I want to pass one of them to a function to use it. Something like this:

fn sort<T>(sorter: dyn Sorter, arr: &mut Vec<T>) {
    sorter::sort(arr);
}

Also is it possible to add them in lets say a Vec and iterate over it, so I can call the functions from there?

Is this possible, or do I need to make instances of the structs and use methods instead?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    Does this answer your question? [How do I create a heterogeneous collection of objects?](https://stackoverflow.com/questions/27957103/how-do-i-create-a-heterogeneous-collection-of-objects) – Chayim Friedman Jun 14 '22 at 23:06

1 Answers1

3

You can statically parameterise on the sorter type:

fn sort<Strategy: Sorter, T>(arr: &mut Vec<T>, descending: bool) where T: Ord + Copy {
    Strategy::sort(arr, descending);
}

fn main() {
    let mut v: Vec<u8> = Vec::new();
    sort::<SelectionSort, _>(&mut v, false);
}

In other situations you might want to instantiate the structure and work with instance methods, but since the method is generic it can't be dynamically dispatched, therefore it's not super useful. Although I guess you could have an intermediate enum serving as dynamic dispatcher:

fn sort<Strategy: Sorter, T>(strategy: Strategy, arr: &mut Vec<T>, descending: bool) where T: Ord + Copy {
    strategy.sort(arr, descending);
}

enum Dynamic {
    BubbleSort,
    SelectionSort
}
impl Sorter for Dynamic {
    fn sort<T>(&self, arr: &mut Vec<T>, desc: bool) where T: Ord + Copy {
        match self {
            Self::BubbleSort => sort(BubbleSort, arr, desc),
            Self::SelectionSort => sort(SelectionSort, arr, desc),
        }
    }
}

fn main() {
    let mut v: Vec<u8> = Vec::new();
    sort(Dynamic::BubbleSort, &mut v, false);
}
Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • Incidentally you don't even need a type for that, you can parameterize on the function (via the `Fn` trait and its friends) directly. – Masklinn Jun 15 '22 at 07:01