- the book
- E0117
- RFC 1023 orphan rules에 대한 설명, we limit the use of negative reasoning to obey the orphan rules. That is, just as a crate cannot define an impl
Type: Trait
unlessType
orTrait
is local, it cannot rely thatType: !Trait
holds unlessType
orTrait
is local. - Reason of Why Restriction Is Valid
- 러스트의 확장성에는 제한이 걸려있다. 적어도 트레잇 또는 타입이 현재 크레이트에 있어야만 한다. 그렇지 않은 경우에는 "NewType" 패턴을 사용하여 현재 스코프에 간단한 래퍼 타입을 만드는 것으로 문제 해결이 가능하고, 심지어 zero-cost-abstraction이라서 부담없이 사용할 수 있다.
다음 코드는 컴파일 에러가 발생한다.
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 }
}