2016-05-31 4 views
0

構造体を囲む構造体があります。Builder構造体があります。これらのラッパーは、Builderに特化した動作を提供します。これらのラッパー間の変換は、本質的には特殊なメソッドを使用したBuilderのように簡単に行う必要があります。私は説明するためにいくつかのコードを書いた - それは何かのための定型文のように思える。より良い方法がありますか?一般的な内部フィールドを共有する構造体にFromとIntoを使用するより良い方法がありますか

struct Builder; 

trait ObjectBuilder: Into<Builder> + From<Builder> { 
    fn from_other<T: ObjectBuilder>(x: T) -> Self { 
    let builder = x.into(); 
    builder.into() 
    } 
} 

struct OtherBuilder { 
    inner: Builder 
} 

impl From<Builder> for OtherBuilder { 
    fn from(x: Builder) -> OtherBuilder { 
     OtherBuilder { 
      inner: x 
     } 
    } 
} 

impl Into<Builder> for OtherBuilder { 
    fn into(self) -> Builder { 
     self.inner 
    } 
} 

struct OtherOtherBuilder { 
    inner: Builder 
} 

impl From<Builder> for OtherOtherBuilder { 
    fn from(x: Builder) -> OtherOtherBuilder { 
     OtherOtherBuilder { 
      inner: x 
     } 
    } 
} 

impl Into<Builder> for OtherOtherBuilder { 
    fn into(self) -> Builder { 
     self.inner 
    } 
} 

impl ObjectBuilder for OtherBuilder {} 
impl ObjectBuilder for OtherOtherBuilder {} 

fn main() { 
    let x = Builder; 
    let y: OtherBuilder = x.into(); 
    let z: OtherOtherBuilder = ObjectBuilder::from_other(y); 
    let y = OtherBuilder::from_other(z); 
} 

Playground URL

Gist URL

+2

あなたは[newtype_derive](https://danielkeep.github.io/rust-custom-derive/doc/newtype_derive/indexを使用することができます.html)crateしかし、それはタプル構造体、すなわち 'struct OtherBuilder(Builder)'でのみ動作します。 – kennytm

答えて

2

代わりのラッパーの構造体を定義し、あなたがこの方法で呼び出すことができる追加機能を提供のみBuilderに実装されているBuilder –すなわち形質のための拡張特性を定義することができます(func(builder)の代わりにbuilder.func())を呼び出します。次に、適切なスコープ(モジュールスコープ、関数スコープなど)に関連する特性のみをインポートすることができます。

同じアプローチの欠点は、同じ名前のメソッドを提供する複数の特性を持つ場合、メソッド呼び出し構文でこれらのメソッドを呼び出すと、(複数のスレッドが関連スコープにインポートされている場合)曖昧になります。コンパイラはあなたがどのような特性を参照しているのかわかりません。確かに、通常の関数構文(MyBuilderExt::func(builder))を使用して呼び出しを明確にすることはできますが、それはあまり意味がありません。その場合、おそらくラッパーはより良いアプローチです。

2

あなたはマクロを使って、あなたのコード内で繰り返しを減らすことができます

struct Builder; 

trait ObjectBuilder: Into<Builder> + From<Builder> { 
    fn from_other<T: ObjectBuilder>(x: T) -> Self { 
    let builder = x.into(); 
    builder.into() 
    } 
} 

macro_rules! builder { 
    ($name:ident) => { 
     struct $name { 
      inner: Builder 
     } 

     impl From<Builder> for $name { 
      fn from(x: Builder) -> $name { 
       $name { 
        inner: x 
       } 
      } 
     } 

     impl Into<Builder> for $name { 
      fn into(self) -> Builder { 
       self.inner 
      } 
     } 

     impl ObjectBuilder for $name {} 
    } 
} 

builder!(OtherBuilder); 
builder!(OtherOtherBuilder); 

fn main() { 
    let x = Builder; 
    let y: OtherBuilder = x.into(); 
    let z: OtherOtherBuilder = ObjectBuilder::from_other(y); 
    let y = OtherBuilder::from_other(z); 
} 
関連する問題