2016-09-15 26 views
0

structを使用してPeano数値の適切な実装を構築しようとしましたが、私のジェネリックスのゲームはまだ十分ではないようです。私はジェネリックスのドキュメントを読んでsomeStackOverflowquestionsですが、私のケースに合っていません。一般的な構造体の列挙

私はPeano特性とZeroSucc種類の導入:私がしたかった最初に

impl Peano for Zero {} 
impl<T> Peano for Succ<T> where T: Peano {} 

trait Peano {} 

struct Zero; 
struct Succ<T: Peano>(T); 

を、両方のタイプは、両方の上に抽象化することができるようにするためのPeano形質を実装Peanoの場合std::ops::Addを実装していましたが、間違ったことをすごくやっていることがすぐわかりましたので、より簡単なものから始めることにしました。

trait Enumerate<T: Peano> { 
    fn succ(&self) -> Succ<T>; 
    fn pred(&self) -> Option<T>; 
} 

impl<T> Enumerate<T> for Zero where T: Peano { 
    fn succ(&self) -> Succ<T> { Succ(*self) } // mismatched types: Zero instead of T 
    fn pred(&self) -> Option<T> { None } 
} 

impl<T> Enumerate<T> for Succ<T> where T: Peano { 
    fn succ(&self) -> Succ<T> { Succ(*self) } // mismatched types: Succ<T> instead of T 
    fn pred(&self) -> Option<T> { Some(self.0) } 
} 

私は何が欠けていますか?私は結果をボクシングで実験したが(できるだけ避けたければ)、エラーはちょうどmismatched types: Box<Succ<T>> instead of Box<Peano>に変更されたので、これが役に立つとは思えない。以下

全コード:

trait Peano {} 

#[derive(Debug, Clone, Copy, PartialEq)] 
struct Zero; 

#[derive(Debug, Clone, Copy, PartialEq)] 
struct Succ<T: Peano>(T); 

impl Peano for Zero {} 
impl<T> Peano for Succ<T> where T: Peano {} 

trait Enumerate<T: Peano> { 
    fn succ(&self) -> Succ<T>; 
    fn pred(&self) -> Option<T>; 
} 

impl<T> Enumerate<T> for Zero where T: Peano { 
    fn succ(&self) -> Succ<T> { Succ(*self) } 
    fn pred(&self) -> Option<T> { None } 
} 

impl<T> Enumerate<T> for Succ<T> where T: Peano { 
    fn succ(&self) -> Succ<T> { Succ(*self) } 
    fn pred(&self) -> Option<T> { Some(self.0) } 
} 

答えて

4

あなたが目的を達成しませんEnumerateTを...持っています。

Peano形質を振り返ってみると、それにはがないことがわかります。Succの実装にはパラメータがありますが、その特性自体はありません。

ここでも同じです。

狭い範囲から始めてみましょう:Enumerateこれだけ進めることができます。形質を定義するときは、実装の種類をあらかじめ

  • では不明であるので、あなたが制限することができ非常に便利な、Selfとして現在の型を参照することができます

    • use std::marker::Sized; 
      
      trait Peano {} 
      
      #[derive(Debug, Clone, Copy, PartialEq)] 
      struct Zero; 
      
      #[derive(Debug, Clone, Copy, PartialEq)] 
      struct Succ<T: Peano>(T); 
      
      impl Peano for Zero {} 
      impl<T> Peano for Succ<T> where T: Peano {} 
      
      trait Enumerate: Peano + Sized { 
          fn succ(self) -> Succ<Self>; 
      } 
      
      impl Enumerate for Zero { 
          fn succ(self) -> Succ<Self> { Succ(self) } 
      } 
      
      impl<T> Enumerate for Succ<T> where T: Peano { 
          fn succ(self) -> Succ<Succ<T>> { Succ(self) } 
      } 
      

      興味のあるいくつかのポイント特色名の後: Peano + Sized構文を使用して、形質の実装


    今、実装していないprevメソッドもありました。事は、prevZeroに当てはめるのは無意味です。この場合、私はあなたがNextEnumerateの名前を変更し、私はPrev形質を作成する方法を紹介しますと提案している:

    trait Prev: Peano + Sized { 
        type Output: Peano + Sized; 
        fn prev(self) -> Self::Output; 
    } 
    
    impl<T> Prev for Succ<T> where T: Peano { 
        type Output = T; 
        fn prev(self) -> Self::Output { self.0 } 
    } 
    

    構文type Output: Peano + Sized関連するタイプあり、それはそれぞれの実装がどのタイプを指定することができます特定のケースで使用してください(のユーザーには、どの型を使用するかを推測する必要がなく、特性のがありません)。

    一旦指定(XPrevを実装する場合)、それは外部からの形質内又は<X as Prev>::OutputSelf::Outputとして呼ぶことができます。

    そして形質が独立しているので、あなただけの、実際前任者を持っているPeano番号についてPrev実装を持っています。


    なぜSizedという制約がありますか?

    現時点では、戻り値の型は既知のサイズである必要があります。これは実装上の制限です。実際には、呼び出し側は呼び出し側が戻り値を書き留めるのに十分な領域をスタックに確保する必要があります。

    しかし...タイプレベルの計算ではこれは役に立たない!どうしようか?

    まあ、最初に我々は(Debug出力よりもきれいに)私たちの計算の結果をチェックする便利な方法を追加します。次に

    trait Value: Peano { 
        fn value() -> usize; 
    } 
    
    impl Value for Zero { 
        fn value() -> usize { 0 } 
    } 
    
    impl<T> Value for Succ<T> where T: Value { 
        fn value() -> usize { T::value() + 1 } 
    } 
    
    fn main() { 
        println!("{}", Succ::<Zero>::value()); 
    } 
    

    を...、彼らは何も持っていないのは、それらのメソッドを取り除くみましょう。再加工特性は、このようにしている:

    trait Next: Peano { 
        type Next: Peano; 
    } 
    
    impl Next for Zero { 
        type Next = Succ<Zero>; 
    } 
    
    impl<T> Next for Succ<T> where T: Peano { 
        type Next = Succ<Succ<T>>; 
    } 
    
    fn main() { 
        println!("{}", <Zero as Next>::Next::value()); 
    } 
    

    と:

    trait Prev: Peano { 
        type Prev: Peano; 
    } 
    
    impl<T> Prev for Succ<T> where T: Peano { 
        type Prev = T; 
    } 
    
    fn main() { 
        println!("{}", <<Zero as Next>::Next as Prev>::Prev::value()); 
    } 
    

    さて、あなたは先に行くことができますし、メソッドを持つ特徴を実装する場合は、追加の制約を必要とするかもしれませんが、Addとの共同を実装します。

  • +0

    感謝のように働いた、ありがとう! – ljedrz

    +0

    そして、タイプレベルの計算に関する追加情報をありがとう - 私のtrait-fooは多く改良されました。 – ljedrz

    +1

    @ ljedrz:タイプ・レベルの計算に深く入りたいのであれば、[typenum](https://crates.io/crates/typenum)の箱に興味があるかもしれないことに注意したい。 –

    関連する問題