2015-04-26 4 views
11

Widziałem pytanie podobne do tego, ale nie takie, które mówi mi dokładnie, jak wdrożyć Ord dla struct. Na przykład, następujący:Jak zaimplementować narzędzie Ord dla struktury?

struct SomeNum { 
    name: String, 
    value: u32, 
} 

impl Ord for SomeNum { 
    fn cmp(&self, other:&Self) -> Ordering { 
     let size1 = self.value; 
     let size2 = other.value; 
     if size1 > size2 { 
      Ordering::Less 
     } 
     if size1 < size2 { 
      Ordering::Greater 
     } 
     Ordering::Equal 
    } 
} 

To daje mi błąd:

error: the trait `core::cmp::Eq` is not implemented for the type `SomeNum` [E0277] 

Jak to naprawić? Próbowałem zmieniając wykonawczych:

impl Ord for SomeNum where SomeNum: PartialOrd + PartialEq + Eq {...} 

i dodając odpowiednie partial_cmp i eq funkcje, ale daje mi błąd, że obie te metody nie są członkiem Ord.

+1

* Widziałem pytanie podobne do tego, ale * - proszę ** dołącz linki do tych pytań ** po ich znalezieniu. Dzięki temu odbierający mogą lepiej zrozumieć, jakie wyjaśnienia już przeczytaliście, a które nie mają sensu, w przeciwnym razie grozi nam powtarzanie tego samego, co już wiemy, marnując czas wszystkich! Jest to również dobre dla przyszłych poszukiwaczy, ponieważ mogą oni łatwo przejść do powiązanych pytań. – Shepmaster

Odpowiedz

20

Definicja Ord to:

pub trait Ord: Eq + PartialOrd<Self> { 
    fn cmp(&self, other: &Self) -> Ordering; 
} 

Każdy typ, który implementuje Ord musi także wdrożyć Eq i PartialOrd<Self>. Musisz wdrożyć te cechy dla SomeNum.

Nawiasem mówiąc, twoje wdrożenie wygląda tak, jakby było źle; jeśli porównujesz tylko wartość self.value, self.value > other.value powinno być Greater, a nie Less.

Możesz użyć implementacji Ord na u32, aby pomóc, jeśli chcesz: self.value.cmp(other.value).

Należy również wziąć pod uwagę, że Ord jest zamówieniem łącznie. Jeśli twoja implementacja PartialEq bierze pod uwagę name, twoja implementacja Ord również musi. To może być również użyć krotki dla wygody (co wskazuje, że najważniejszym polem w porównaniu jest value, ale jeśli są one takie same, name powinny być brane pod uwagę), coś takiego:

struct SomeNum { 
    name: String, 
    value: u32, 
} 

impl Ord for SomeNum { 
    fn cmp(&self, other: &Self) -> Ordering { 
     (self.value, &self.name).cmp(&(other.value, &other.name)) 
    } 
} 

impl PartialOrd for SomeNum { 
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 
     Some(self.cmp(other)) 
    } 
} 

impl PartialEq for SomeNum { 
    fn eq(&self, other: &Self) -> bool { 
     (self.value, &self.name) == (other.value, &other.name) 
    } 
} 

impl Eq for SomeNum { } 

Jeśli robisz to w ten sposób, można także zmienić kolejność pól i używać #[derive]:

#[derive(PartialEq, Eq, PartialOrd, Ord)] 
struct SomeNum { 
    value: u32, 
    name: String, 
} 

ta rozwinie się w zasadzie to samo.

+0

Dziękujemy! Jeszcze jedna rzecz. Gdybym chciał ręcznie obliczyć cmp, co powrócił by oznaczać większy, mniejszy lub równy. Próbowałem robić powyższe i zwracając Zamawianie :: Mniej, Zamawianie :: Większe i Zamawianie :: Równe, gdy jest to właściwe, ale kompilator stwierdza, że ​​cmp oczekuje typu wyjściowego() zamiast core :: cmp :: Zamawianie. Wydaje się, że zdarza się to tylko w przypadkach mniejszych i większych, które występują w oświadczeniu if – Dumbapples

+1

O tak, chodziło o 'if size1 size2 {Ordering :: Greater} else { Kolejność :: Równy} '.Wyrażenie "if" ma typ, masz efektywnie trzy wyrazy z rzędu, wartości pierwszych dwóch z nich nie były używane, i które również miały niespójne typy, ponieważ miały one niejawne 'else {}', które jest typu '()'. –

+0

Dobrze. Dzięki jeszcze raz! – Dumbapples