Using the Newtype Pattern to Implement External Traits on External Types

다음 코드는 컴파일 에러가 발생한다.

impl Ord for [i32; 2] {
	fn cmp(&self, other: &Self) -> Ordering {
		if self[0] == other[0] {
			self[1].cmp(&other[1])
		} else {
			self[0].cmp(&other[0])
		}
	}
}

컴파일러가 타입 [i32; 2]이 foreign이고, 동시에 Ord 트레잇 또한 현재 크레이트에 정의되어 있지 않다고 불평을 내고있다.

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
 --> src/main.rs:4:5
  |
4 |     impl Ord for [i32; 2] {
  |     ^^^^^^^^^^^^^--------
  |     |            |
  |     |            this is not defined in the current crate because arrays are always foreign
  |     impl doesn't use only types from inside the current crate
  |
  = note: define and implement a trait or new type instead

For more information about this error, try `rustc --explain E0117`.

해결방법은 다양하다. 하나씩 핥아보고 가자.

Newtype Pattern Inspired by Haskell programming language

래퍼타입을 사용하여 foreign type을 현재 크레이트의 타입인냥 사용할 수 있다.

use core::cmp::*;
#[derive(Eq, PartialEq, PartialOrd)]
struct Wrapper([i32; 2]);

impl Ord for Wrapper {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.0[0] == other.0[0] {
            self.0[1].cmp(&other.0[1])
        } else {
            self.0[0].cmp(&other.0[0])
        }
    }
}
fn main() {
    let lhs = [1, 2];
    let rhs = [3, 4];
    assert!(Wrapper(lhs) < Wrapper(rhs));
    assert!(lhs < rhs); // 기본적으로 배열끼린 비교가 가능했구나
}

Ensure at least one local type is referenced by the impl

래퍼타입을 쓰기 싫다면 From 트레잇을 구현한 임의의 타입으로 대치할 수 있다. (효용성은 잘 모르겠음)

pub struct Foo; // you define your type in your crate

impl Drop for Foo { // and you can implement the trait on it!
    // code of trait implementation here
}

impl From<Foo> for i32 { // or you use a type from your crate as
                         // a type parameter
    fn from(i: Foo) -> i32 {
        0
    }
}

Define a trait locally and implement that instead

타입을 로컬로 만드는 것이 아닌, 트레잇을 로컬로 만드는 전략이다.

trait Bar {
    fn get(&self) -> usize;
}

impl Bar for u32 {
    fn get(&self) -> usize { 0 }
}