Jakub
Jakub

Reputation: 822

How to pass an array of objects implementing a certain trait to a function?

To learn Rust syntax, I've decided to implement a function sorting a passed-in array:

fn sort(array) {
    // actual sorting
}

In this question I found out how to pass an array and change its content, but besides this the array must consist of types that can be compared. I've found the std::cmp::PartialOrd trait and figured out that the elements of an array need to implement it.

By connecting this knowledge with the paragraph about dynamic dispatch in the Rust book I've built something like this:

use std::cmp;

fn sort(arr: &mut [&std::cmp::PartialOrd]) {
    // actual sorting
}

This doesn't compile:

error[E0393]: the type parameter `Rhs` must be explicitly specified
 --> src/lib.rs:3:21
  |
3 | fn sort(arr: &mut [&std::cmp::PartialOrd]) {
  |                     ^^^^^^^^^^^^^^^^^^^^ missing reference to `Rhs`
  |
  = note: because of the default `Self` reference, type parameters must be specified on object types

Is there a correct syntax to achieve passing an array of objects implementing a certain trait to a function?

Upvotes: 6

Views: 3131

Answers (2)

basic_bgnr
basic_bgnr

Reputation: 737

The issue is the function definition.

fn sort(arr: &mut [&std::cmp::PartialOrd]) {
    // actual sorting
}

If you modify your function to include a type parameter, you can compile the program:

fn sort<T>(arr: &mut [T])
where
    T: PartialOrd,
{
}

fn main() {}

Note that you are not actually passing an array but a slice. In Rust, an array is defined by the type it holds as well as its length.

a: [i32; 10] // defines an array that stores `i32` and has length 10
a: [i32] // defines a slice of i32

Also note that the PartialOrd trait is included by default when the program is compiled, so there's no need to use a fully qualified name. You can use PartialOrd rather than std::cmp::PartialOrd. See std::prelude.

Upvotes: 3

fjh
fjh

Reputation: 13091

Syntax isn't really the problem here. I'll try to explain why what you want to do is a bit dodgy, so you probably won't get this to work with trait objects:

The argument of your sort function has the type &mut [&std::cmp::PartialOrd]. In general, &mut [&Trait]) means "a mutable slice of values of any type at all, as long as they implement Trait". Note, however, that the values in the slice may have different types. The question arising from this is: what should happen in sort if the slice contains values of different values, e.g. Float and String? Just because floats can be compared and strings can be compared does not mean that you can meaningfully compare a float to a string. This is basically what the error message is pointing out.

The syntax you're using is fine. For example, the following (which might sort the array by the string representation of the elements) compiles:

fn sort(arr: &mut [&ToString]) {
    // sort by string representation
}

But what you probably actually want to do is just use a generic function as follows (since dynamic dispatch doesn't really make much sense here):

fn sort<T: PartialOrd>(arr: &mut [T]) {
    // do the sorting
}

This is similar to your original code, but it defines sort for any type T that implements PartialOrd. The important difference to your code is that the elements in the slice all have to be of the same type, so the issue what to do with values of different types doesn't arise.

Upvotes: 7

Related Questions