Is there any way to create a type alias for multiple traits?
Asked Answered
H

3

55

I have a generic function that prints the minimum of two items:

use std::fmt::Display;

fn print_min<T: PartialOrd + Display>(a: &T, b: &T) {
    println!("min = {}", if a < b { a } else { b });
}

This works pretty well with anything that implements both the PartialOrd and Display traits:

print_min(&45, &46);
// min = 45
print_min(&"a", &"b");
// min = a

Having to put the PartialOrd + Display in the function definition is kind of ugly, especially if I want to have a whole bunch of functions that operate on this (implementing a binary search tree, for example), or if my bounds get more complex. My first inclination was to attempt to write a type alias:

type PartialDisplay = PartialOrd + Display;

but this gives me some fairly bizarre compiler errors:

error[E0393]: the type parameter `Rhs` must be explicitly specified
 --> src/main.rs:7:23
  |
7 | type PartialDisplay = PartialOrd + Display;
  |                       ^^^^^^^^^^ missing reference to `Rhs`
  |
  = note: because of the default `Self` reference, type parameters must be specified on object types

error[E0225]: only auto traits can be used as additional traits in a trait object
 --> src/main.rs:7:36
  |
7 | type PartialDisplay = PartialOrd + Display;
  |                                    ^^^^^^^ non-auto additional trait

I'm guessing either my syntax is wrong or this just isn't possible yet. I'd like something like

type PartialDisplay = ???
fn print_min<T: PartialDisplay> { /* ... */ }
Headword answered 27/9, 2014 at 1:59 Comment(1)
You can write a macro trait_alias as described in #30292084Oscilloscope
A
76

PartialOrd and Display are traits. It has been discussed how to implement an alias but it was decided that it wasn't needed.

Instead, you can create a new trait with the traits you want as super traits and provide a blanket implementation:

use std::fmt::Display;

trait PartialDisplay: PartialOrd + Display {}
impl<T: PartialOrd + Display> PartialDisplay for T {}

fn print_min<T: PartialDisplay>(a: &T, b: &T) {
    println!("min = {}", if a < b { a } else { b });
}

fn main() {
    print_min(&45, &46);
    print_min(&"aa", &"bb");
}
Adamsen answered 27/9, 2014 at 4:3 Comment(1)
Thanks for linking to the discussion, makes more sense now why it was decided not to include it.Headword
C
34

RFC 1733 introduced the concept of a trait alias. When it is stabilized, you will be able to say:

#![feature(trait_alias)]

use std::fmt::Display;

trait PartialDisplay<Rhs = Self> = PartialOrd<Rhs> + Display;

fn print_min<T: PartialDisplay>(a: &T, b: &T) {
    println!("min = {}", if a < b { a } else { b });
}

fn main() {
    print_min(&45, &46);
    print_min(&"a", &"b");
}
Chicago answered 13/3, 2018 at 18:58 Comment(1)
Note that according to a comment on this issue, the "trait alias" feature is actually more powerful than the verbose work around in the top answer here, because it also properly handles trait bounds on associated types.Eureka
L
5

While awaiting the stabilization of trait aliasing, you can use the trait-set crate. Here is an example of its use:

trait-set! {
    pub trait HashKey = Hash + Eq + Clone
}
Ledesma answered 9/12, 2021 at 22:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.