使用Option <t>创建一个通用结构,而不使用None

时间:2017-02-09 15:51:24

标签: rust

我有一个

struct Foo<T>
where
    T: // ... some complex trait bound ...
{
    a: Bar,
    b: Option<T>,
}

当尝试使用b: None实例化结构时,编译器会抱怨它无法推断出类型并需要类型提示,例如通过turbofish语法。这对调用者来说是繁重的,因为他们必须找到一个满足特征界限的类型并导入它,尽管不关心这个可选功能。

我认为我正在寻找的是底部类型,它会自动满足任何特征界限但无法实例化以便None::<Bottom>可以使用,但我在文档中没有找到这样的类型。

2 个答案:

答案 0 :(得分:3)

a feature in the works允许将从不输入指定为!。这在稳定的Rust中不存在,因此您需要使用nightly和feature标志:

#![feature(never_type)]

fn thing<T>() -> Option<T> {
    None
}

fn main() {
    thing::<!>();
}

然而,这对你的情况不起作用(这是它不稳定的部分原因):

#![feature(never_type)]

trait NothingImplementsMe {}

fn thing<T>() -> Option<T> 
    where T: NothingImplementsMe,
{
    None
}

fn main() {
    thing::<!>();
}
error[E0277]: the trait bound `!: NothingImplementsMe` is not satisfied
  --> src/main.rs:12:5
   |
12 |     thing::<!>();
   |     ^^^^^^^^^^ the trait `NothingImplementsMe` is not implemented for `!`
   |
   = note: required by `thing`

关于跟踪问题的第一个未解决的问题是:

  

我们应该为!实施哪些特征?

由于此功能既不稳定又无法满足您的需求,您可能需要考虑创建自己的定制“底部”类型:

trait AlmostNothingImplementsMe {
    fn foo();
}

struct Nope;
impl AlmostNothingImplementsMe for Nope {
    fn foo() { unimplemented!() }
}

fn thing<T>() -> Option<T> 
    where T: AlmostNothingImplementsMe,
{
    None
}

fn main() {
    thing::<Nope>();
}

为了改善这方面的用户体验,我建议创建一种类型的构建器,让你以仿底类型开始:

mod nested {
    pub trait AlmostNothingImplementsMe {
        fn foo();
    }

    pub struct Nope;
    impl AlmostNothingImplementsMe for Nope {
        fn foo() { unimplemented!() }
    }

    pub fn with_value<T>(t: T) -> Option<T> 
        where T: AlmostNothingImplementsMe,
    {
        Some(t)
    }

    pub fn without_value() -> Option<Nope> {
        None
    }
}

fn main() {
    nested::without_value();
}

您可以看到这种类似的模式in crates like Hyper,虽然它会将具体类型打包,因此您无法从外部看到它。

答案 1 :(得分:2)

避免使用turbofish运算符的一个选项是使用类型别名:

trait MyTrait {}
impl MyTrait for () {}

struct Foo<T: MyTrait> {
    i: isize,
    o: Option<T>,
}

type Bar = Foo<()>;

fn main() {
    let foo_default = Bar { i: 1, o: None };
}

我使用()作为默认设置的默认设置,但{@ 1}}(如果可用)或您自己的底部类型,如@ Shepmaster的答案可能更好。

如果你不介意!或类似的话,构造函数也可以工作。