Rust 默认泛型参数

Rust 默认泛型参数,rust,traits,Rust,Traits,我有一个可以用builder模式构建的结构,因为有一些选项al字段 如果使用生成器函数指定这些可选字段,则不必指定常规参数 但是如果我不调用这些函数,我需要指定泛型参数 以下是一个例子: use Structs::*; struct Struct<T, F: Fn(T)> { func: Option<F>, value: T, } enum Structs<T, F: Fn(T)> { Struct1(T), Struct

我有一个可以用builder模式构建的结构,因为有一些
选项
al字段

如果使用生成器函数指定这些可选字段,则不必指定常规参数

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

以下是一个例子:

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();
}
应指定
F
类型取决于
T

我尝试指定默认类型参数,如下所示:

impl<T, F: Fn(T) = Box<Fn(T)>> Struct<T, F> {
impl结构{
但这并不能解决问题

那么,如何避免在
Struct::new()
调用中指定类型参数呢


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

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

首先,我们需要为
F
指定一个初始类型。我们可以选择
Fn(T)
的任何现有实现,但我们可以做得更好。我建议我们使用,这样可以清楚地看到,当
F
是该类型时,
选项
(您不能构造
一些(x)
因为对于空类型没有有效的
x
)。这种方法的一个缺点是,对于类型(闭包除外)实现
Fn
FnMut
FnOnce
是不稳定的,需要夜间编译器

#![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 {}
    }
}
impl
不是
F
上的泛型:
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结构{
fn func(自身,func:F1)->Struct{
结构{
func:Some(func),
价值:自我价值,
}
}
}
此方法需要保留在
Struct
上的
F
type参数的泛型
impl
块中,以便可以在已调用
func
的生成器上使用。但是,
func
本身也必须是泛型的,以便它可以接收任何类型的函数(而不是一个与构建器类型匹配的函数)。然后,我们必须构建一个新的
结构,而不是变异
self
,因为我们不能仅仅将
结构
强制为
结构

,下面是一个类似的想法,可以在稳定的情况下工作:

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

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

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

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

    fn build(self) -> Structs<T, F> {
        use Structs::*;

        if let Some(func) = self.func {
            Struct2(self.value, func)
        } else {
            Struct1(self.value)
        }
    }
}

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

    let _strct = Struct::new(42).build();
}
从评论中回答我自己的问题:


如果没有为
t
F
指定具体类型,那么Rust编译器应该分配多少空间来存储
Struct

在64位机器上,
fn()
的大小为8个字节,导致整个结构总共有16个字节:

std::mem::size_of::<fn()>();
std::mem::size_of_val(&strct);
std::mem::size_of::();
std::mem::val的大小(&strct);
但是,当您给它一个具体的回调时,结构只需要8个字节!这是因为回调的类型是单态的,它不需要状态,基本上可以内联


Francis Gagné的解决方案在每种情况下只需要8个字节,因为
Void
类型的大小为零!

如果不为
t
F
指定具体的类型,那么Rust编译器应该分配多少空间来存储
Struct
?@Shepmaster,理论上,如果编译器可以确定
F
从未使用过,它只能将该字段写入大小为0的字段。当然,问题是这种整个程序的推理非常复杂。@Jsor一个有趣的观点,但正如您所提到的,Rust不会在单个函数边界之外进行任何推理。@Shepmaster您能详细说明或提供一些关于确认的参考资料吗“Rust不会在单个函数边界之外进行任何推断”?理论上,
结构
甚至可以进一步优化:由于
选项
某些
变量无法实例化,因此只剩下
变量。具有单个变量的枚举不需要判别式(虽然现在看来,单位枚举仍然有一个判别式),而且由于
None
不包含任何数据,因此
选项的大小可以是零。因此
结构的大小应该是4而不是8。
struct Struct<T, F: Fn(T)> {
    func: Option<F>,
    value: T,
}

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

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

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

    fn build(self) -> Structs<T, F> {
        use Structs::*;

        if let Some(func) = self.func {
            Struct2(self.value, func)
        } else {
            Struct1(self.value)
        }
    }
}

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

    let _strct = Struct::new(42).build();
}
impl<T> Struct<T, &'static Fn(T)> {
    fn new(value: T) -> Struct<T, &'static Fn(T)> {
std::mem::size_of::<fn()>();
std::mem::size_of_val(&strct);