2017-02-14 1 views
1

newコンストラクタを1つ2つの引数で使用しようとしていますが、これを行う方法がわかりません。現時点でも可能ですか?私が今持っている何異なる数の引数を持つ関数をオーバーロードすることは可能ですか(形質を使用します)

はそれがなく、実用的だ方法で、技術的に可能である私の範囲内にある複数の該当項目というエラー(playground

trait __Constructor1<T> { 
    fn new(T) -> Self; 
} 
trait __Constructor2<T, U> { 
    fn new(T, U) -> Self; 
} 

enum MixedInts { 
    SmallInt(i32), 
    TwoSmallInts(i32, i32), 
} 

impl __Constructor1<i32> for MixedInts { 
    fn new(__0: i32) -> MixedInts { 
     MixedInts::SmallInt(__0) 
    } 
} 
impl __Constructor2<i32, i32> for MixedInts { 
    fn new(__0: i32, __1: i32) -> MixedInts { 
     MixedInts::TwoSmallInts(__0, __1) 
    } 
} 

fn main() { 
    let x = MixedInts::new(2i32); 
    let y = MixedInts::new(2i32, 2i32); 
} 
+1

私はあなただけの小さな例を作成しようとした知っている..しかし、ここでの形質の使用はかなり無駄です。あなたの例を少し頭に変えて、私はこの技術をいくつかのコードベースで使用しています(https://play.rust-lang.org/?gist=2ae7e995af81de014bd8a59971021649&version=stable&backtrace=0)。 –

+0

@SimonWhitehead私はあなたのコードが達成するはずのものがわかりません。引数の数はまったく受け入れず、何らかの理由で列挙型の代わりに第2の型を作成します。 – JelteF

+0

この目的は、enum_の_useを関数の「オーバーロード」の方法として示すことです。列挙型を使用して、さまざまな数の引数を関数に渡すことができます。したがって、 "オーバーロード"のメカニズムとして列挙型を使用することで、その頭の上にあなたの例を反転させます - 私は例として列挙型が主要な部分であることを強調する例として構造体を使用しました。 –

答えて

7

を与えます。 newへの呼び出しを明確にするために、RustのUniversal Function Call Syntaxを使用する必要があります。

fn main() { 
    let x = <MixedInts as __Constructor1<i32>>::new(2i32); 
    let y = <MixedInts as __Constructor2<i32, i32>>::new(2i32, 2i32); 
} 

鉄のフレームワークは、私ははあなたが望むものを実現考える面白いModifier patternを持っています。それはかなり賢いですが、それは最終的にユーザーに混乱しています。

4

錆は、オーバーロードされた関数/メソッドをサポートしていません。この問題を回避するには、タプルを使用して単一の引数で複数の値を受け取ることができます。次に、特性を定義し、その単一の引数の許容可能な型に対して実装することができます。この関数は、特性の実装に単純に委譲します。

enum MixedInts { 
    SmallInt(i32), 
    TwoSmallInts(i32, i32), 
} 

trait IntoMixedInts { 
    fn into(self) -> MixedInts; 
} 

impl MixedInts { 
    fn new<A>(args: A) -> MixedInts 
     where A: IntoMixedInts 
    { 
     args.into() 
    } 
} 

impl IntoMixedInts for i32 { 
    fn into(self) -> MixedInts { 
     MixedInts::SmallInt(self) 
    } 
} 

impl IntoMixedInts for (i32, i32) { 
    fn into(self) -> MixedInts { 
     MixedInts::TwoSmallInts(self.0, self.1) 
    } 
} 

fn main() { 
    let x = MixedInts::new(2i32); 
    let y = MixedInts::new((2i32, 2i32)); 
} 

注:この例では、あなたの代わりに独自の特性を定義する標準FromInto特性を使用することができます。しかし、コヒーレンスルール(特定のタイプの特定の特性の実装が1つしかないことを保証するルール)のために、他の特性では機能しない可能性があります。

enum MixedInts { 
    SmallInt(i32), 
    TwoSmallInts(i32, i32), 
} 

impl MixedInts { 
    fn new<A>(args: A) -> MixedInts 
     where A: Into<MixedInts> 
    { 
     args.into() 
    } 
} 

impl From<i32> for MixedInts { 
    fn from(a: i32) -> MixedInts { 
     MixedInts::SmallInt(a) 
    } 
} 

impl From<(i32, i32)> for MixedInts { 
    fn from((a, b): (i32, i32)) -> MixedInts { 
     MixedInts::TwoSmallInts(a, b) 
    } 
} 

fn main() { 
    let x = MixedInts::new(2i32); 
    let y = MixedInts::new((2i32, 2i32)); 
} 
+0

注:Rustは、特性を使ったオーバーロードをサポートしています。 Into/Fromを使用するよりも実用的ではありませんが、サポートされています。 –

-1

私は標準ライブラリにFrom/Intoの特性を利用してお勧めします。

#[derive(PartialEq, Eq, Debug)] 
enum MixedInts { 
    SmallInt(i32), 
    TwoSmallInts(i32, i32), 
} 

impl From<i32> for MixedInts { 
    fn from(n: i32) -> Self { 
     MixedInts::SmallInt(n) 
    } 
} 

impl From<(i32, i32)> for MixedInts { 
    fn from((a, b): (i32, i32)) -> Self { 
     MixedInts::TwoSmallInts(a, b) 
    } 
} 

fn main() { 
    let x: MixedInts = 2_i32.into(); 
    assert_eq!(x, MixedInts::SmallInt(2)); 

    let y: MixedInts = (2_i32, 2_i32).into(); 
    assert_eq!(y, MixedInts::TwoSmallInts(2, 2)); 
} 

example on Rust Playground

+0

これは[FromとIntoを使用して提案されている既存の回答]とどのように異なるのかを明確にすることができますか(http://stackoverflow.com/a/42238787/155423)? – Shepmaster

+0

唯一の違いは、From/Into実装を利用するためにmainの中のコードを置き換えたことです。 – ampron

関連する問題