From, TryFrom 트레잇 (Feat. Into, TryInto)
포스트
취소

From, TryFrom 트레잇 (Feat. Into, TryInto)

개요

From 트레잇을 사용하면, 다른 타입을 대상 타입으로 변환할 수 있습니다.

이미 많이 사용해왔던 기능인데, String::from("foo") 등으로 사용해왔던 트레잇입니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use std::convert::*;

#[derive(Debug, PartialEq)]
struct Foo {
    bar: usize,
}

impl From<usize> for Foo {
    fn from(item: usize) -> Self {
        Foo { bar: item }
    }
}

let x = Foo::from(5);
assert_eq!(x, Foo { bar: 5 });

하지만 Box<T>같은 타입은 new 메서드를 사용해서 Box를 생성할 수 있습니다. (물론 From 트레잇도 구현되어 있으나, 둘 모두 같은 기능을 합니다.)

그럼 왜 굳이 From 트레잇을 구현하는가 하면, 매우 간단명료하게 대답할 수 있습니다:

Boxnewfrom은 제네릭 T를 받고, fromnew를 호출합니다.
(제네릭 T를 받지 않는 타입(ex, String) 같은 경우, new 보단 from이 더욱 편합니다.)

그러므로 newfrom 메서드의 기능은 똑같지만, 후술할 Into 덕분에 from이 존재합니다.

Into

IntoFrom을 구현하면 자동으로 구현됩니다. 다만, 사용 방법이 조금 다릅니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use std::convert::*;

#[derive(Debug, PartialEq)]
struct Foo {
    bar: usize,
}

impl From<usize> for Foo {
    fn from(item: usize) -> Self {
        Foo { bar: item }
    }
}

let x = Foo::from(5);
assert_eq!(x, Foo { bar: 5 });

let x: Foo = 5usize.into();
assert_eq!(x, Foo { bar: 5 });

into를 사용할 땐, 컴파일러가 어떤 타입인지 모르기 때문에, 타입 어노테이션을 명시해주어야 합니다.

TryFrom, TryInto

관련 자료 등을 찾아보면 TryFromTryInto가 존재하는 것을 알 수 있는데, 이들은 이름 그대로 반환되는 값이 Result<T, E>의 경우일 때 사용합니다.

대표적으로, 타입 변환을 사용할 때 이용됩니다:

1
let x: Result<i64, _> = 5i32.try_into();

타입으로 쓰인 _는 반환 값을 무시하는 _ = expr; 문법이 아닌, infer 타입을 뜻합니다.

TryFrom 또한, From 트레잇과 비슷하게 구현할 수 있습니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use std::convert::*;

#[derive(Debug, PartialEq)]
struct Foo {
    bar: usize,
}

impl TryFrom<usize> for Foo {
    type Error = &'static str;

    fn try_from(value: usize) -> Result<Self, Self::Error> {
        if value != 0 {
            Ok(Foo { bar: value })
        } else {
            Err("Error")
        }
    }
}

let x = Foo::try_from(5);
assert_eq!(x, Ok(Foo { bar: 5 }));

let x = Foo::try_from(0);
assert_eq!(x, Err("Error"));

let _: Foo = 5usize.try_into().unwrap();

다만 차이점은, Error라는 연관 타입(associated type)이 존재하는데, 그냥 Result<T, E>의 제네릭 E 입니다.