2017-04-27 4 views
3

포맷터의 공통 인터페이스를 만들고 싶습니다. 입력기를 사용하여 목적에 따라 형식을 지정합니다.빈 구조체 구현을 반환하는 팩토리 클래스 만들기

현재 Formatter 구현을 포함하는 Box를 반환합니다 (결과로 래핑 됨). 그러나 이것이 이것이 최선의 방법이라고 생각하지 않습니다. Formatter 구현은 빈 구조체이므로 Box에 힙 메모리를 할당하는 것은 의미가 없습니다.

pub trait Formatter { 
    fn format_information(&self, information: Result<Information, Error>) -> Result<String, Error>; 
    fn format_information_collection(&self, information: InformationCollection) -> Result<String, Error>; 
} 

pub struct JsonFormatter; 
impl Formatter for JsonFormatter {...} 

pub struct XmlFormatter; 
impl Formatter for XmlFormatter {...} 


// Factory to create a formatter 
pub struct Factory; 
impl Factory { 
    pub fn get_formatter(format: &str) -> Result<Box<Formatter>, Error> { 
     match format { 
      "json" => Ok(Box::new(JsonFormatter {})), 
      "xml" => Ok(Box::new(XmlFormatter {})), 
      _ => Err(Error::new(format!("No formatter found for format {}", format))) 
     } 
    } 
} 

// Use the factory 
let formatter_box = Factory::get_formatter(format).unwrap(); 
let formatter = &*formatter_box as &Formatter; 

녹에서 올바른 방법은 무엇입니까?

답변

10

포매터 구현은 빈 구조체이므로 Box에 대한 힙 메모리 할당은 의미가 없습니다.

그리고 의미가 없으므로 힙 메모리가 전혀 할당되지 않습니다. 의이 (Playground)을 해보자 :

// `()` doesn't occupy any space, like e.g. your `JsonFormatter` 
let b1 = Box::new(()); 
let b2 = Box::new(()); 

println!("{:p}\n{:p}", &*b1, &*b2); 

이 출력을 생성합니다

0x1 
0x1 

ZSTs (제로 크기의 종류) 종종 특별한 방법으로 처리됩니다. 따라서 적어도 여기에서는 힙 할당에 대한 비용을 지불하지 않는다는 것을 알고 있습니다. 그러나 Box<Formatter>의 메모리 레이아웃은 뚱뚱한 포인터이며 다음과 같습니다 : (*mut Formatter, *mut VTable). 첫 번째 포인터는 항상 0x1이고, 두 번째 포인터는 함수 포인터 (vtable - Wikipedia)를 포함하는 정적으로 할당 된 디스패치 테이블을 가리 킵니다. 이것은 아마도 귀하의 상황에서 괜찮을 것입니다.


또 다른 가능성은 다음과 같이 열거 만드는 것입니다 :

enum FormatterSd { 
    Json(JsonFormatter), 
    Xml(XmlFormatter), 
} 

을 그리고 지금 당신은 Formatter for FormatterSd을 구현할 수 있습니다; 이 구현에서는 간단한 match 블록을 사용하여 디스패치를 ​​수행합니다. 그렇게하면 Box을 사용할 필요가 없습니다.


마지막으로 : 공장 유형은 필요하지 않습니다. 당신이 강력하게 OO 프로그래밍 언어에서 녹에 아이디어를 가져 오기 위해 노력하는 것 같아요. 종종 이것이 최고의 또는 가장 관용적 인 해결책은 아닙니다. 예를 들어, Rust에는 무료 함수가 있습니다. 따라서 간단히 다음과 같이 쓸 수 있습니다 :

fn get_formatter(format: &str) -> Result<Box<Formatter>, Error> { 
    // ... 
} 

예, Factory 유형을 사용하지 마십시오! empty 타입은 Rust에서 빈 클래스보다 훨씬 덜 일반적입니다 (의미 없음 : 필드 없음). 당신은 단지 이런 종류의 것들을 위해 자유로운 함수를 사용할 수 있습니다. 유형과 연관시킬 필요가 없습니다.

그리고 마지막으로 마지막 : 수동 Box A로부터의 참조를 취득 할 필요가 없습니다은 :

let formatter = &*formatter_box as &Formatter; 

당신은 간단 formatter_box.format_information(...);, 덕분에 강제 변환을 DEREF을 말할 수있다.

+0

답장을 보내 주셔서 감사합니다. 나는 많이 배웠다. 나는 Rust로 시작하고 내 workday 언어는 PHP 다. :) – cundd