Rust Trait std::convert

jollidah·2023년 7월 22일
0
post-thumbnail

std::convert

이 module 내부에 있는 trait은 다른 타입을 변환하는 module이고, 각 trait은 각각의 목적을 제공한다.

  • AsRef은 cheap reference-to-reference conversion을 제공한다.
  • AsMut은 cheap mutable-to-mutable conversion을 제공한다.
  • From은 value를 consuming하는 value-to-value conversion을 제공한다.
  • Into는 value를 consuming하고, 현재 crate 외부에 있는 type value-to-value을 conversion을 제공한다.
  • TryFromTryInto trait은 FromInto와 같이 작동하지만, conversion이 fail할 수도 있을 때 써야 한다. trait은 다양한 type의 arguments와 같은 경우를 위한 generic 함수에도 활용된다.

FromTryFrom이 더 유연하고 standard library의 blanket implementation(포괄적 구현) 덕에 IntoTryInto의 기능도 제공하기 때문에, Into<U>TryInto<U> 보다는 From<T>TryFrom<T>를 사용할 것을 권장한다.

AsRef

pub trait AsRef<T>
where
    T: ?Sized,
{
    // Required method
    fn as_ref(&self) -> &T;
}

cheap reference-to-reference conversion을 제공함. mutable reference 사이의 conversion을 제공하는AsMut와 유사하다. 보다 costly(비싼) conversion을 하기 위해선 &TFrom을 사용하는 것이 좋다.

Relation to Borrow

AsRefBorrow와 유사하지만, 몇가지 다른 점이 있다.

  • AsRef와 달리 Borrow는 모든 T를 위한 blanket impl(포괄적인 구현)을 갖고 있고, reference와 value를 받을 수 있다.
  • Borrow는 borrowed value의 Hash, Eq 그리고 Ord가 owned value의 그것과 동일해야 한다. 따라서, struct의 single field를 빌리길 원한다면, AsRef로 구현할 수 있다.

AsRef example

struct의 value에 다한 참조를 immutable 참조로 변환한다. 단 주의할 점은 모든 field의 type에 따라 선언해줘야 한다는 점이다. 아래 예시에선 i32 타입과 String타입에 맞춰서 구현했다.

use std::convert::AsRef;

#[derive(Debug)]
struct number {
    i32: i32,
    string: String
}

impl AsRef<i32> for number{
    fn as_ref(&self) -> &i32 {
        &self.i32
    }
}

impl AsRef<String> for number{
    fn as_ref(&self) -> &String {
        &self.string
    }
}

fn main(){
    let c = number{
        i32: 1,
        string: "value: 1".to_string(),
    };

    let n: &i32 = c.as_ref();
    println!("{}", n);

    let p: &String = c.as_ref();
    println!("{}", p);
}

AsMut

pub trait AsMut<T>
where
    T: ?Sized,
{
    // Required method
    fn as_mut(&mut self) -> &mut T;
}

cheap mutable-to-mutable reference conversion을 제공한다. AsRef와 유사하지만, mutable reference끼리 변환할 때 사용한다. 이 trait은 절대 fail해선 안된다. 만약 conversion이 fail할 수도 있는 경우, Opion<T>Result<T>를 반환하는 dedicated method를 사용하자.
모든 mutably dereferenceable type에 해당되는 말은 아니지만, AsMut는 inner type이 mutable reference라면 auto-deference를 한다. (e.g: 만약 foo&mut Foo혹은 &mut &mut Foo type을 갖고 있다면 foo.as_mut()는 동일하게 작동한다. foo.as_mut()BOX::new(foo)as.mut()와 동일하게 작동하지 않는다. 많은 smart pointer는 cheap reference-to-reference 변환을 하진 않지만, pointed-to value를 반환하며 as_mut의 기능을 제공한다. 하지만, AsMut::as_mut은 mutable dereferencing의 목적으로만 사용하지 말아야 한다.

let mut x = Box::new(5i32);
// Avoid this:
// let y: &mut i32 = x.as_mut();
// Better just write:
let y: &mut i32 = &mut x;

AsMut example

mutable 참조 (&mut T)와 AsMut trait을 이용해 참조를 mutable 참조로 바꾸는 둘의 차이점은 참조되는 값의 type이다. AsMut trait을 사용하면 모든 유형의 값에 대한 참조를 동일한 값에 대한 변경 가능한 참조로 변환할 수 있다.

use std::convert::AsRef;
use std::fmt::Debug;

#[derive(Debug)]
struct number {
    i32: i32,
    string: String,
}

impl AsMut<i32> for number {
    fn as_mut(&mut self) -> &mut i32 {
        &mut self.i32
    }
}

fn modify_asmut<T: AsMut<i32> + ?Sized> (v: &mut T, value: i32){
    *v.as_mut() = value;
}

fn main() {
    let mut c = number {
        i32: 1,
        string: "value: 1".to_string(),
    };
    let w = &mut c;
    w.i32 = 3;
    println!("{:?}", w); // 3

    modify_asmut(w, 4);
    println!("{:?}", w);
}

From

Intoreciprocal(역수)다. From trait은 type별로 생성자를 overloading할 수 있게 해준다. 물론 rust에서 생성자(constructor) 개념은 존재하지 하지만 않지만 이해를 위해서 생성자라는 단어를 사용했다.

use std::fmt::Debug;

#[derive(Debug)]
struct number {
    i32: i32,
    string: String,
}

impl From<i32> for number {
    fn from(item: i32) -> number{
        number { 
            i32: item,
            string: item.to_string()
        }
    }
}
fn main() {
    let t: number = From::from(4);
    println!("{:?}", t);
}	// number { i32: 4, string: "4" }

Into

Fromreciprocal(역수)다. From trait을 구현했다면 따로 함수를 추가하지 않아도 된다.

use core::num;
use std::fmt::Debug;

#[derive(Debug)]
struct number {
    i32: i32,
    string: String,
}

impl From<i32> for number {
    fn from(item: i32) -> number{
        number { 
            i32: item,
            string: item.to_string()
        }
    }
}
fn main() {
    let t: number = 4.into();
    println!("{:?}", t);
}	// number { i32: 4, string: "4" }
profile
٩( ᐛ )و 

1개의 댓글

comment-user-thumbnail
2023년 7월 22일

좋은 글 감사합니다.

답글 달기