2017-04-27 12 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であり、2番目のポインタは関数ポインタ(vtable - Wikipedia)を含む静的に割り当てられたディスパッチテーブルを指しています。これはおそらくあなたの状況では問題ありません。


別の可能性としては、このような列挙型を作成することです:

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

をそして今、あなたはFormatter for FormatterSdを実装することができます。この実装では、単純なmatchブロックを使用してディスパッチを行います。あなたはBoxを使う必要はありません。


最後に、工場の種類は必要ありません。それはあなたが強いOOプログラミング言語のアイデアをRustにもたらすようになっているようです。多くの場合、これは最善の方法ではありません。たとえば、Rustには無料の関数があります。したがって、あなたは簡単に書くことができます:

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

はい、Factoryタイプなし!空のクラスは、空のクラス(意味:フィールドを持たない)よりもはるかに一般的ではありません。この種のものには自由な関数を使うだけで、型に関連付ける必要はありません。

そして最後に最後に:あなたは手動でBoxからの参照を取得する必要はありません。

let formatter = &*formatter_box as &Formatter; 

あなたは、型変換をDEREFのおかげで、formatter_box.format_information(...);シンプル言うことができます。

+0

ありがとうございました。私は多くのことを学びました。私はRustから始まり、私の就業日の言語はPHPです:) – cundd

関連する問題