Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

arrays

rust

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?

like image 313
Jakub Avatar asked Oct 04 '15 10:10

Jakub


People also ask

How do you pass an array of values to a function?

Answer: An array can be passed to a function by value by declaring in the called function the array name with square brackets ( [ and ] ) attached to the end. When calling the function, simply pass the address of the array (that is, the array's name) to the called function.

How do you pass an array of objects as a parameter?

Passing array of objects as parameter in C++ It can be declared as an array of any datatype. Syntax: classname array_name [size];

What is passed when we pass an array as a function argument?

In C language when we pass an array as a function argument, then the Base address of the array will be passed.


2 Answers

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.

like image 128
fjh Avatar answered Oct 08 '22 08:10

fjh


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.

like image 45
basic_bgnr Avatar answered Oct 08 '22 07:10

basic_bgnr