RUST에서 서로 다른 유형의 여러 개체를 보유하기 위한 이기종 유형 생성

Rust 내에서 사용할 수 있는 유형은 동종 유형의 구성을 지원하며 다음과 같은 유형에서 사용할 수 있습니다.

Vec<T>;  // an vector
[T;N];   // an array
();      // tuple 


필요한 다양한 시나리오에 따라 사용할 수 있는
이기종 유형으로 사용할 수 있지만 컴파일 시간 동안 적용되는 Sized 특성에 의해 자연스럽게 제한되어 동적으로 추가로 사용하도록 제한됩니다.

여기서 주목해야 할 핵심 사항은 유형에서 도출할 수 있는 공통 관계를 기반으로 유형을 분리할 수 있다는 것입니다.

그러나 Rust에서 이기종 유형을 지원하는 경우 포인터 뒤에 있는 vtable의 개체를 가리키는 dyn 특성을 사용하여 사용 가능한 여러 유형의 개체를 수용할 수 있는 유형을 구성하는 것이 약간 까다로워집니다.
당신은 읽을 수 있습니다 here ,

런타임 중에 유형의 크기를 조정할 수 있기를 원하므로 개체를 저장할 수 있는 Vec<T> 유형을 선택하겠습니다.

이 특성을 적용하는 유형이 두 가지 기술을 사용하여 개체를 직접 참조할 수 있기 때문입니다.

1) 객체에 대한 참조 사용

   Vec<&dyn yourTrait>;


2) Box 스마트 포인터 뒤에 개체 배치

  Vec<Box<dyn youTrait>>;



특성의 이름이 Foo이고 구현될 하나의 메서드를 선언한다고 가정해 보겠습니다.

trait Foo {
  fn call(&self);
}


이제 우리는 이것을 구현할 임의의 유형을 만들 것입니다.
다음과 같다
(단순화를 위해 여기서는 튜플 구조체를 정의했지만 유형은 이것보다 훨씬 더 복잡할 수 있습니다 ... 특성을 구현하는 한 괜찮을 것입니다)

#[derive(Debug)]
struct A(i32); 
impl Foo for A {
    fn call(&self) {
        println!("type A: {:?}", self.0);
    }
}

#[derive(Debug)]
struct B(i32); 
impl Foo for B {
    fn call(&self) {
        println!("type B: {:?}", self.0);
    }
}

#[derive(Debug)]
struct C(i32); 
impl Foo for C {
    fn call(&self) {
        println!("type C: {:?}", self.0);
    }
}


여기에서 모든 유형이 특성 메소드의 동일한 정확한 정의를 구현하지만 해당 유형으로 수행하려는 작업에 따라 다를 수 있다는 이상한 점을 관찰할 수 있습니다.


이제 간단하게 저장할 수 있는 유형 선언을 시작하겠습니다.
첫 번째 방법에 따라

*1) 객체에 대한 직접 참조 사용 *

여기서 주목해야 할 한 가지 중요한 점은 유형에 제공할 참조가 변경 가능하거나 변경 불가능하다는 것입니다!



즉, 모든 특성 객체에 균일하게 적용되며 일부 특성 객체는 가변적으로 전달되고 다른 특성 객체는 불변으로 전달될 수 없습니다.

fn main() {
     //some random trait objects declared
    let a = &A(43); 
    let b = &B(73); 
    let c = &C(95); 

     // now we will compose our homogenous type based on the previously types
    let objs: Vec<&dyn Foo> = vec![a, b, c];

    for I in objs.iter() {
       I.call(); 
    }
}


객체a, b, c가 각각 유형A, B, C에 대한 참조를 보유하고 있으므로 여기에서 직접 전달하여 동종 유형을 구성할 수 있습니다.
출력 :

type A: 43
type B: 73
type C: 95



2) Box 스마트 포인터 사용하기

이제 우리는 또 다른 흥미로운 방법을 시도할 것입니다. 이 경우 객체를 Box 스마트 포인터 뒤에 배치합니다. 이 경우 컴파일 자체 중에 특성 객체를 초기화하는 것에 대해 걱정할 필요가 없습니다. 대신 포인터 포인팅 뒤에 배치합니다. 힙의 메모리 위치로
이 기술에서는 차용 규칙이 적용되지 않기 때문에 함께 작업하는 것이 상당히 설득력이 있습니다.
또한 플러스 측면은 객체가 초기화될 수 있다는 것입니다. 추가적인 이점인 런타임 동안



fn main() {

    //here we place our objects behind a box pointer 
    let a = Box::new(A(43)); 
    let b = Box::new(B(73)); 
    let c = Box::new(C(95)); 

    //our type hold a boxed trait object as type to accept
    let mut objs: Vec<Box<dyn Foo>> = vec![a,b,c] ;

    for I in objs.iter() {
        I.call();
    }

}


여기서 출력은 이전 출력과 정확히 동일하지만 상자 포인터의 더 많은 기능이 있습니다.

type A: 43
type B: 73
type C: 95


거기 당신은 .. 새로운 유형을 만드는 방법을 성공적으로 배운 것을 축하합니다 >>



😊 여기까지 읽어주셔서 감사합니다 🥂🎉🎊!

의견, 제안, 의심 또는 조언이 있는 경우 의견 섹션에 자유롭게 게시하십시오.

좋은 웹페이지 즐겨찾기