2017-03-05 8 views
2

からパラメータなしの変異体を作成します。私はバリアントのコンストラクタに値を与えることによって、列挙値を構築することができるようにしたい空のタプル

use self::Variants::*; 

#[derive(Clone, Debug)] 
enum Variants { 
    Unit(()), 
    One(u8), 
} 

fn emit<C: Fn(S) -> T, S, T>(constructor: C, value: S) -> T { 
    constructor(value) 
} 

fn main() { 
    let unit: Variants = emit(&Unit,()); 
    println!("{:?}", unit); // Prints Unit(()). 
    let one: Variants = emit(&One, 10); 
    println!("{:?}", one); // Prints One(10). 
} 

問題この例で、私はUnit(())の代わりに()を必要とするということですより一般的なUnit(パラメータなし)。

私は専門を使用してみました:

#![feature(specialization)] 

trait Constructor<S, T> { 
    fn construct(self, value: S) -> T; 
} 

impl<T> Constructor<(), T> for T { 
    fn construct(self, _value:()) -> T { 
     self 
    } 
} 

impl<F: Fn(S) -> T, S, T> Constructor<S, T> for F { 
    default fn construct(self, value: S) -> T { 
     self(value) 
    } 
} 

fn emit<C: Constructor<I, R>, I, R>(callback: &C, value: I) -> R { 
    callback.construct(value) 
} 

use self::Variants::*; 

#[derive(Clone, Debug)] 
enum Variants { 
    Unit, 
    One(u8), 
} 

fn main() { 
    let unit: Variants = emit(&Unit,()); 
    println!("{:?}", unit); // Should prints Unit. 
    let one: Variants = emit(&One, 10); 
    println!("{:?}", one); // Prints One(10). 
} 

が、これはとコンパイル時に失敗します。これらの impl秒の誰もサブセットではありませんので、 RFCの私の理解から

conflicting implementations of trait `Constructor<(), _>`: 

、これが失敗もう一方の第1のimplfor TTが第2の実施のfor FFより一般的であるからであると私は考える。したがって、それは専門化することはできません。一方

Tが前者に二回書き込まれるためConstructor<(), T> for T(さらにConstructor<S, T> for T)がConstructor<S, T> for Fより特異的であるので、一般的な(default)実装することができません。

これはRFCを読んだことから私の理解です。私が間違っているかどうか教えてください。

Unitに無用なパラメータを指定しなくても、最初の例の動作をどうすればできますか?

ナイトリーコンパイラを必要とするソリューションにはオープンしています。

答えて

1

VariantsにはFnを実装するとどうなりますか? (注:FnFnMut必要としFnMutFnOnce必要ですので、我々はすべての3つを実装する必要があります。)

#![feature(fn_traits)] 
#![feature(unboxed_closures)] 

use self::Variants::*; 

#[derive(Clone, Debug)] 
enum Variants { 
    Unit, 
    One(u8), 
} 

impl FnOnce<((),)> for Variants { 
    type Output = Variants; 

    extern "rust-call" fn call_once(self, args: ((),)) -> Self::Output { 
     self.call(args) 
    } 
} 

impl FnMut<((),)> for Variants { 
    extern "rust-call" fn call_mut(&mut self, args: ((),)) -> Self::Output { 
     self.call(args) 
    } 
} 

impl Fn<((),)> for Variants { 
    extern "rust-call" fn call(&self, _: ((),)) -> Self::Output { 
     self.clone() 
    } 
} 

fn emit<C: Fn(S) -> T, S, T>(callback: &C, value: S) -> T { 
    callback(value) 
} 

fn main() { 
    let unit: Variants = emit(&Unit,()); 
    println!("{:?}", unit); // Prints Unit. 
    let one: Variants = emit(&One, 10); 
    println!("{:?}", one); // Prints One(10). 
} 

このソリューションの唯一の奇妙な側面は、あなたが今emitの最初の引数としてなど&One(10)を値を渡すことができることです(ただし、2番目の引数は()に限られます)。