从空元组创建不带参数的变量

时间:2017-03-05 22:00:06

标签: rust

我希望能够通过为变量构造函数赋值:

来构造枚举值
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).
}

但是在编译时失败了:

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

根据我对RFC的理解,这失败了,因为这些impl中没有一个是另一个的子集。我认为这是因为第一个T的{​​{1}}中的for T比第二个实现的impl的{​​{1}}更通用。因此,它不能是专业化。

另一方面,它不能是一般的(F)实现,因为for F(甚至default)比Constructor<(), T> for T更具体,因为{{1}在前者写了两次。

这是我阅读RFC的理解。请告诉我,如果我错了。

如何在不向Constructor<S, T> for T提供无用参数的情况下使第一个示例正常工作?

我对需要夜间编译器的解决方案持开放态度。

1 个答案:

答案 0 :(得分:1)

Fn实施Variants怎么样? (注意:Fn需要FnMutFnMut需要FnOnce,因此我们必须实施这三项。)

#![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).
}

此解决方案唯一奇怪的方面是您现在可以将&One(10)之类的值作为第一个参数传递给emit(尽管第二个参数只能是())。 / p>