Umbrella method call for methods in different Types

โš“ Rust    ๐Ÿ“… 2025-06-01    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 3      

surdeus

Warning

This post was published 71 days ago. The information described in this article may have changed.

Dear rust people,

I'm a novice of Rust and trying to test the limits of my understanding of the language, so bear with me if this code is very stupid and/or non-idiomatic within Rust.

Coming from a science background and working with Python, I'm used to methods like .sort() working out-of-the-box on a dynamic array containing numbers. Now while working in Rust I've come to learn there are inherent difficulties sorting mutable vectors containing floats. While I found that one can use .sort() for Vec<i32> and the like, and .sort_by(f64::total_cmp) for Vec, I have attempted to make a generic do_sort() method which works on vectors of any type of number Type:

  6 // Custom trait for all types that can be sorted with .sort()
  7 pub trait CanSort: std::cmp::Ord {}
  8
  9 impl CanSort for i32 {}
 10 impl CanSort for u32 {}
 11 impl CanSort for i64 {}
 12 impl CanSort for u64 {}
 13 //impl CanSort for char {}  // you rarely work with Vec<char>, instead it's commonly Vec<&str>
 14 //impl CanSort for &str {}  // may not want to accept &str as this can fail during conversion to f64, and requires extra code
 15
 16 // Let's first implement a trait that will be common for all our array slices with numbers:
 17 pub trait CustomSort {
 18     fn do_sort(&mut self);
 19 }
 20
 21 // All Types which implement Ord use self.sort()
 22 impl<T: CanSort> CustomSort for Vec<T> {
 23     fn do_sort(&mut self) {
 24         self.sort();
 25     }
 26 }
 27 // For f64
 28 impl CustomSort for Vec<f64> {  // Do we need to change this to implement f64 instead of Vec<f64>?
 29     fn do_sort(&mut self) {
 30         self.sort_by(f64::total_cmp);
 31     }
 32 }
 33 // For f32
 34 impl CustomSort for Vec<f32> {
 35     fn do_sort(&mut self) {
 36         self.sort_by(f32::total_cmp);
 37     }
 38 }
 39

This code does what i want it to: I can create a: Vec<f64> = vec!([2.2, 3.3, 1.1]) and run a.do_sort() and it works as expected. I can also use this function directly as a library:

use crate::customsort::{CustomSort};
pub mod customsort;

fn main() {
    let list_f64: [f64; 3] = [2.2, 3.3, 1.1];
    let mut f64v: Vec<f64> = Vec::from(list_f64);

    let list_i64: [i64; 3] = [2, 3, 1];
    let mut i64v: Vec<i64> = Vec::from(list_i64);

    f64v.do_sort();
    i64v.do_sort();

    assert_eq!(f64v, Vec::from([1.1_f64, 2.2, 3.3]));
    assert_eq!(i64v, Vec::from([1_i64, 2, 3]));
}

But I would like to be able to use .do_sort() within a function. This is where I encounter a lot of problems:

use crate::customsort::{CustomSort, CanSort};
pub mod customsort;

fn main() {
    let mut f64v: Vec<f64> = Vec::from([2.2, 3.3, 1.1]);

    test_do_sort(&mut f64v);
}

fn test_do_sort<T>(v: &mut Vec<T>)
where
    T: CustomSort + CanSort + Copy + Ord + std::fmt::Debug
{
    v.do_sort();
}

with cargo run this produces the error:

error[E0277]: the trait bound `f64: CustomSort` is not satisfied
  --> src/main.rs:77:18
   |
77 |     test_do_sort(&mut f64v);
   |     ------------ ^^^^^^^^^ the trait `CustomSort` is not implemented for `f64`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the following other types implement trait `CustomSort`:
             Vec<T>
             Vec<f32>
             Vec<f64>
note: required by a bound in `test_do_sort`
  --> src/main.rs:82:8
   |
80 | fn test_do_sort<T>(v: &mut Vec<T>)
   |    ------------ required by a bound in this function
81 | where
82 |     T: CustomSort + CanSort + Copy + Ord + std::fmt::Debug
   |        ^^^^^^^^^^ required by this bound in `test_do_sort`

error[E0277]: the trait bound `f64: CanSort` is not satisfied
  --> src/main.rs:77:18
   |
77 |     test_do_sort(&mut f64v);
   |     ------------ ^^^^^^^^^ the trait `CanSort` is not implemented for `f64`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the following other types implement trait `CanSort`:
             i32
             i64
             u32
             u64
note: required by a bound in `test_do_sort`
  --> src/main.rs:82:21
   |
80 | fn test_do_sort<T>(v: &mut Vec<T>)
   |    ------------ required by a bound in this function
81 | where
82 |     T: CustomSort + CanSort + Copy + Ord + std::fmt::Debug
   |                     ^^^^^^^ required by this bound in `test_do_sort`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `common_collections_samples` (bin "common_collections_samples") due to 2 previous errors

While I understand that Rust complains that I'm trying to create a function which accepts Types which have both traits CustomSort and CanSort, which have no overlap, I'm struggling to figure out a way to allow all Types that have either of these traits, as both provide an implementation for do_sort() for the different Types. I can't add f32 or f64 to CanSort, as these are not members of trait Ord and can't be sorted with the typical .sort().

I've been stuck on this for more than a day, and would be very happy for any help or pointers to a better way of achieving the same goal (without relying on a separate Crate, since I want to understand better how to do this myself, not just get a finished implementation of .sort()).

Many thanks
// Andrรฉ

2 posts - 2 participants

Read full topic

๐Ÿท๏ธ rust_feed