100 Exercised To Learn Rust - 4.9 From 풀기

4.8 Sized

Sized 트레이트는 어떤 타입이 런타임에만 크기를 알 수 있는 DST(Dynamically sized types)이 아니라, 컴파일 시간에 크기를 알 수 있는, 이미 크기가 정해진(sized) 타입이라는 것을 알려준다.

 

어떤 행동도 구현할 필요 없는 Marker 트레이트이자, 타입 정의에 따라 자동으로 구현되는 Auto 트레이트다.

 

&str은 참조로서 포인터를 가질 뿐 아니라 길이 필드도 갖고 있다. 하지만 포인터와 길이 필드는 usize로 컴파일 시간에 크기를 알 수 있으므로, &strSized다.

From

pub trait From<T>: Sized {
    fn from(value: T) -> Self;
}

pub trait Into<T>: Sized {
    fn into(self) -> T;
}

 

std::convert 모듈에는 위와 같은 트레이트가 정의되어 있는데, 슈퍼 트레이트(supertrait)와 묵시적 트레이트 바운드(implicit trait bounds)라는 개념이 들어 있다.

슈퍼 트레이트

From<T>: Sized 는 FromSized의 서브 트레이트(subtrait)임을 암시한다(Sized는 From의 슈퍼 트레이트).

From을 구현하는 타입이라면 반드시 Sized도 구현해야 한다.

묵시적 트레이트 바운드

명시적으로 선언되지 않은 트레이트 바운드가 코드의 다른 부분에서 자동으로 추론되는 것을 의미한다.

컴파일러는 제네릭 타입 파라미터를 Sized로 간주한다.

따라서 From은 실제로는 아래와 같다. 제네릭 타입 T역시 Sized여야 한다.

pub trait From<T: Sized>: Sized {
    fn from(value: T) -> Self;
}

 

부정 트레이트 바운드(Negative trait bound)를 사용하면 Sized 바운드를 해제할 수 있다.

pub struct Foo<T: ?Sized> {
    //            ^^^^^^^
    //            This is a negative trait bound
    inner: T,
}

 

"TSized일 수도 있고 아닐 수도 있다"를 의미한다. 그러므로 T를 DST에 바인딩할 수 있다.

 

FromInto는 Dual 트레이트로, IntoFrom을 구현하는 모든 타입에 대하여 blanket 구현을 사용해 구현된다.

 

blanket 구현(blanket implementation)은 모든 타입에 대한 트레이트 또는 특정 조건과 일치하는 모든 타입에 대한 트레이트를 구현한 것이다.

impl<T, U> Into<U> for T
where
    U: From<T>,
{
    fn into(self) -> U {
        U::from(self)
    }
}

 

타입 UFrom<T>를 구현한다면, T에 대해 Into<U>도 자동으로 구현된다.

 

그래서 실제로는 &str에 대한 Into<String>이 구현되어 있지 않지만, String에 대한 From<&str>은 구현되어 있으므로 let title = "A title".into()와 같이 작성할 수 있다.

 

blanket 구현의 다른 예로는 DisplayToString이 있다.

impl<T> ToString for T
where
    T: Display + ?Sized,
{ ... }

 

ToString을 구현하는 모든 타입은 Display 타입 역시 구현한다.

풀이

// TODO: WrappingU32에 대해 example이 컴파일되도록 From 트레이트를 구현하세요.

pub struct WrappingU32 {
    value: u32,
}

impl From<u32> for WrappingU32 {
    fn from(value: u32) -> WrappingU32 {
        WrappingU32 { value }
    }
}
fn example() {
    let wrapping: WrappingU32 = 42.into();
    let wrapping = WrappingU32::from(42);
}

 

u32 타입으로부터 WrappingU32를 반환하는 From 트레이트를 구현한다.

 

From 트레이트는 from 함수를 갖고 있다. u32 타입을 받아 WrappingU32 타입으로 반환한다.

 

함수 본문은 WrappingU32 구조체에 u32 타입 매개변수 value를 넣는다.