Есть ли способ создать псевдоним типа для нескольких признаков?

У меня есть общая функция, которая печатает минимум два элемента:

use std::fmt::Display;

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

Это хорошо работает со всем, что реализует черты PartialOrd и Display:

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

Наличие PartialOrd + Display в определении функции довольно уродливо, особенно если я хочу иметь целый набор функций, которые работают с этим (например, реализуя двоичное дерево поиска), или если мои границы становятся более сложными. Первым делом я попытался написать псевдоним типа:

type PartialDisplay = PartialOrd + Display;

но это дает мне довольно странные ошибки компилятора:

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

Я предполагаю, что либо мой синтаксис неправильный, либо это просто невозможно. Я хотел бы что-то вроде

type PartialDisplay = ???
fn print_min<T: PartialDisplay> { /* ... */ }

Ответ 1

PartialOrd и Display являются чертами. Обсуждали, как реализовать псевдоним, но было решено, что он не нужен.

Вместо этого вы можете создать новую черту с теми чертами, которые вы хотите использовать как супер-черты, и обеспечить полную реализацию:

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");
}

Ответ 2

RFC 1733 ввел понятие черты псевдонима. Когда стабилизируется, вы сможете сказать:

#![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");
}