rust - 默认泛型参数

标签 rust traits

我有一个可以使用构建器模式构建的结构,因为有一些Optional 字段。

如果我使用构建器函数来指定这些可选字段,则不必指定通用参数。

但是如果我不调用这些函数,我需要指定泛型参数。

这是一个例子:

use Structs::*;

struct Struct<T, F: Fn(T)> {
    func: Option<F>,
    value: T,
}

enum Structs<T, F: Fn(T)> {
    Struct1(T),
    Struct2(T, F),
}

impl<T, F: Fn(T)> Struct<T, F> {
    fn new(value: T) -> Struct<T, F> {
        Struct {
            func: None,
            value: value,
        }
    }

    fn build(self) -> Structs<T, F> {
        if let Some(func) = self.func {
            Struct2(self.value, func)
        }
        else {
            Struct1(self.value)
        }
    }

    fn func(mut self, func: F) -> Struct<T, F> {
        self.func = Some(func);
        self
    }
}

fn main() {
    let _strct = Struct::new(42)
        .func(|n| { println!("{}", n); })
        .build();

    //let _strct = Struct::new(42).build(); // Does not compile.
    let _strct = Struct::<_, &Fn(_)>::new(42).build();
}

我想在未设置可选字段时省略类型注释,如下所示:

let _strct = Struct::new(42).build();

需要说明的是F类型依赖于T

我试着指定一个默认类型参数:

impl<T, F: Fn(T) = Box<Fn(T)>> Struct<T, F> {

但这并没有解决问题。

那么我怎样才能避免在 Struct::new() 调用中指定类型参数呢?

如果无法避免这种情况,是否有任何替代构建器模式的方法可以让我省略类型注释?

最佳答案

有一种方法可以通过在构建器演化过程中更改其类型来解决此问题。自 Struct::func获取构建器的所有权并返回一个新的构建器,我们可以自由更改结果类型。

首先,我们需要为 F 指定一个初始类型.我们可以为 Fn(T) 选择任何现有的实现,但我们可以做得更好。我建议我们使用 empty/void/uninhabited/bottom type ,所以很明显当F是那种类型,然后是OptionNone (你不能构造 Some(x) 因为没有有效的 x 用于空类型)。这种方法的一个缺点是实现 Fn , FnMutFnOnce对于类型(闭包除外)不稳定,需要夜间编译器。

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

enum Void {}

impl<T> FnOnce<T> for Void {
    type Output = ();

    extern "rust-call" fn call_once(self, _args: T) {
        match self {}
    }
}

impl<T> FnMut<T> for Void {
    extern "rust-call" fn call_mut(&mut self, _args: T) {
        match *self {}
    }
}

impl<T> Fn<T> for Void {
    extern "rust-call" fn call(&self, _args: T) {
        match *self {}
    }
}

接下来,让我们移动Struct::new到另一个impl block :

impl<T> Struct<T, Void> {
    fn new(value: T) -> Struct<T, Void> {
        Struct {
            func: None,
            value: value,
        }
    }
}

implF不是通用的: new只会生成 Struct其中 F = Void .这避免了在 func 的情况下出现歧义。永远不会被调用。

最后,我们需要制作func更改构建器的类型:

impl<T, F0: Fn(T)> Struct<T, F0> {
    fn func<F1: Fn(T)>(self, func: F1) -> Struct<T, F1> {
        Struct {
            func: Some(func),
            value: self.value,
        }
    }
}

此方法需要保留在 impl 中在 F 上通用的 block 在 Struct<T, F> 上输入参数, 这样它就可以用在 func 的构建器上已经被调用了。然而,func本身也必须是通用的,以便它可以接收任何类型的函数(而不是匹配构建器类型的函数)。然后,而不是变异 self ,我们必须构建一个新的 Struct ,因为我们不能强制使用 Struct<T, F0>进入 Struct<T, F1> .

关于rust - 默认泛型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37310941/

相关文章:

scala - 只允许在同一个包内继承

rust - 特征的生命周期作为返回值

rust - 我如何支持 Serde 枚举的未知值或其他值?

rust - 声明具有可变大小(在编译时已知)的数组类型的语法?

rust - 多文件 Rust 项目

c++ - 从 trait 获取 const 或非常量引用类型

rust - 有没有办法让 serde_json 严格反序列化?

rust - 如何在每一步将一些值传输到 Rust 生成器中?

php - 任何人都知道用于特征在类中重新定义的名称的 PHP 魔法常量?

rust - 闭包返回类型的生命周期规范