Ответ 1
Типы объектов-черт имеют связанный срок жизни, но его можно опустить. Тип объекта с полным признаком пишется dyn Trait + 'a
(когда за ссылкой стоит добавить круглые скобки: &(dyn Trait + 'a)
).
Сложность состоит в том, что когда ограничение на время жизни опущено, правила немного усложняются.
Во-первых, мы имеем:
impl PartialOrd for dyn SimpleOrder {
Здесь компилятор выводит + 'static
. Параметры времени жизни никогда не вводятся в блоках impl
(по состоянию на Rust 1.32.0).
Далее имеем:
fn partial_cmp(&self, other: &dyn SimpleOrder) -> Option<Ordering> {
Предполагается, что тип other
равен &'b (dyn SimpleOrder + 'b)
, где 'b
- это неявный параметр времени жизни, введенный в partial_cmp
.
fn partial_cmp<'a, 'b>(&'a self, other: &'b (dyn SimpleOrder + 'b)) -> Option<Ordering> {
Итак, теперь у нас есть, что self
имеет тип &'a (dyn SimpleOrder + 'static)
то время как other
имеют тип &'b (dyn SimpleOrder + 'b)
. В чем проблема?
Действительно, cmp
не дает никакой ошибки, потому что его реализация не требует, чтобы время жизни двух объектов trait было одинаковым. Почему partial_cmp
заботится, хотя?
Потому что partial_cmp
вызывает Ord::cmp
. Когда тип проверяет вызов метода черты, компилятор проверяет сигнатуру черты. Давайте рассмотрим эту подпись:
pub trait Ord: Eq + PartialOrd<Self> {
fn cmp(&self, other: &Self) -> Ordering;
Эта черта требует, чтобы other
были типа " Self
. Это означает, что когда partial_cmp
вызывает cmp
, он пытается передать a &'b (dyn SimpleOrder + 'b)
параметру, который ожидает &'b (dyn SimpleOrder + 'static)
a &'b (dyn SimpleOrder + 'static)
, потому что Self
является dyn SimpleOrder + 'static
. Это преобразование недопустимо ('b
не может быть преобразовано в 'static
), поэтому компилятор выдает ошибку.
Итак, почему допустимо устанавливать тип other
на &'b (dyn SimpleOrder + 'b)
при реализации Ord
? Поскольку &'b (dyn SimpleOrder + 'b)
является супертипом &'b (dyn SimpleOrder + 'static)
, а Rust позволяет заменять тип параметра одним из его супертипов при реализации метода trait (это делает метод строго более общий, хотя он явно не используется при проверке типов).
Чтобы сделать вашу реализацию как можно более универсальной, вы должны ввести параметр времени жизни для impl
s:
use std::cmp::Ordering;
pub trait SimpleOrder {
fn key(&self) -> u32;
}
impl<'a> PartialOrd for dyn SimpleOrder + 'a {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> Ord for dyn SimpleOrder + 'a {
fn cmp(&self, other: &Self) -> Ordering {
self.key().cmp(&other.key())
}
}
impl<'a> PartialEq for dyn SimpleOrder + 'a {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
impl<'a> Eq for dyn SimpleOrder + 'a {}