2016-09-15 4 views
0

struct을 사용하여 Peano 숫자의 적절한 구현을 시도하려고했지만 제네릭 게임이 아직 충분하지 않아서 도움이 될 것 같습니다. 제네릭에 대한 문서를 읽고 someStackOverflowquestions,하지만 내 경우에는 맞지 않습니다. 일반 구조체 열거

은 내가 Peano 특성 및 ZeroSucc 유형 소개 :

trait Peano {} 

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

를 그리고 두 유형 모두에 걸쳐 추상적 할 수 있도록하기위한 Peano 특성 구현 : 처음에는

impl Peano for Zero {} 
impl<T> Peano for Succ<T> where 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

당신은 어떤 용도로 사용하지 Enumerate에서 T을 ...있다.

Peano 특성을 되돌아 보면 이 없음을 알 수 있습니다. Succ의 구현에는 매개 변수가 있지만 특성 자체는 없습니다.

동일하게 적용됩니다.

좁은 범위부터 시작해 보겠습니다. Enumerate 앞으로 나아갈 수 있습니다. 관심의

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

몇 가지 포인트 :

이 에게
    당신이 Self으로 현재의 형식을 참조 할 수
  • 는, 구현의 종류 때문에 특성을 정의하는 매우 유용 할 때하는 것은 사전에 알 수
  • 당신은 제한 할 수 형질 이름

,617 후 : 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은을 유형, 그것은에있는 유형을 지정하기 위해 각각의 구현을 허용 관련 특정 경우에 사용하십시오 (사용자가 어떤 유형을 사용해야하는지 추측 할 필요없이 특성의을 피하십시오).일단 지정된

, 그것은 형질 내의 Self::Output로 지칭 될 수도 있고, 외부로부터 <X as Prev>::Output 등 (X 구현 Prev 경우).

그리고 특성이 분리 된 이후

, 당신은 실제로 전신이 Peano 번호에 대한 Prev 구현을 가지고있다.


Sized의 제약이 있습니까?

현재 Rust는 리턴 유형이 알려진 크기를 요구합니다. 이것은 구현 한계입니다. 실제로 호출자는 반환 값을 기록하기 위해 호출 수신자가 스택에 충분한 공간을 확보해야합니다.

그러나 ... 유형 수준의 계산을 위해 이것은 쓸모가 없습니다! 그래서, 우리는 무엇을합니까?

글쎄, 우선합니다 (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

그리고 타입 - 레벨 계산에 관한 추가 정보를 주셔서 감사합니다 - 나의 특성 - foo가 많이 향상되었습니다. – ljedrz

+1

@ ljedrz : 유형 수준 계산에 "깊이"들어가기를 원한다면 [typenum] (https://crates.io/crates/typenum) 상자에 관심이있을 수 있습니다. –

관련 문제