简体   繁体   English

使用Option创建通用结构 <T> 无实例化时不指定T

[英]Create a generic struct with Option<T> without specifying T when instantiating with None

I have a 我有一个

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

When attempting to instantiate the struct with a b: None the compiler complains that it cannot infer the type and requires a type hint eg via the turbofish syntax. 尝试使用b: None实例化结构时b: None编译器抱怨它无法推断类型,并且需要类型提示,例如通过turbofish语法。 That is onerous on the caller because they will have to find a type that fulfills the trait bounds and import it despite not caring about that optional functionality. 这对调用者来说是很麻烦的,因为他们将不得不找到一个满足特征范围的类型并导入它,尽管它并不关心该可选功能。

I think what I am looking for would be a bottom type that automatically fulfills any trait bounds but cannot be instantiated so that None::<Bottom> could be used, but I have not found such a type in the documentation. 我认为我正在寻找的是底部类型,该类型可以自动满足任何特征范围,但是无法实例化,因此可以使用None::<Bottom> ,但是我在文档中没有找到这种类型。

There's a feature in the works that allows specifying the never type as ! 作品中有一个功能 ,可以将永不类型指定为! . This is not present in stable Rust, so you need to use a nightly and a feature flag: 在稳定的Rust中不存在此功能,因此您需要使用每晚和功能标记:

#![feature(never_type)]

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

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

However, this doesn't work for your case yet (this is part of the reason that it's unstable): 但是,这还不适用于您的情况(这是不稳定的部分原因):

#![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`

The very first unresolved question on the tracking issue is: 关于跟踪问题的第一个未解决的问题是:

What traits should we implement for ! 我们应该实现什么特征! ?


Since this feature is both unstable and doesn't do what you want, you may want to consider creating your own bespoke "bottom" type: 由于此功能既不稳定又不能满足您的要求,因此您可能需要考虑创建自己的定制“底部”类型:

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>();
}

To improve the UX of this, I'd suggest creating a builder of some type that starts you off with the faux-bottom type: 为了改善用户体验,我建议创建某种类型的构建器,让您从仿底类型开始:

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();
}

You can see this similar pattern in crates like Hyper , although it boxes the concrete type so you don't see it from the outside. 您可以在类似Hyper的板条箱中看到这种类似的模式,尽管它装箱了具体的类型,所以您不会从外面看到它。

One option to avoid the need to the turbofish operator is to have a type alias: 避免对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 };
}

I used () as the default for simplicity, but ! 为了简单起见,我使用()作为默认值,但是! (when available) or your own bottom type as in @Shepmaster's answer may be better. (如果有)或@Shepmaster的答案中您自己的底部类型可能更好。

A constructor function could also work if you don't mind Foo::new_default(i) or similar. 如果您不介意Foo::new_default(i)或类似的函数,则构造函数也可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么不能为通用选项克隆 None<t> 当 T 不实现克隆?</t> - Why can't None be cloned for a generic Option<T> when T doesn't implement Clone? 在通用结构上派生反序列化时,无法解析T:serde :: Deserialize <'a> - Cannot resolve T: serde::Deserialize<'a> when deriving Deserialize on a generic struct 为什么在返回类型选项时返回 None<T> 当 T 不是引用时不返回空指针 - Why is returning None when of return type option<T> not return the null pointer when T is not a reference 当传递给 function 中的泛型闭包时,泛型结构的寿命不够长 - Generic struct doesn't live long enough when passed to generic closure in function 创建一个在另一个通用结构上通用的结构 - Create a struct that is generic over another generic struct 为什么Option的Some和None变体不需要合格? - Why don't Option's Some and None variants need to be qualified? 如何转换期权 <Result<T, Error> &gt;选项 <T> 没有打开它吗? - How to convert a Option<Result<T, Error>> to an Option<T> without unwrapping it? 从 Rust 中的通用结构内部调用 T::new() - Calling T::new() from inside generic struct in Rust Drop 不能用于实现扩展 trait 的泛型结构 - Drop can't be used in the generic struct implementing extended trait Rust:从 function 返回一个通用结构,其中(仅)<t> 是不同的</t> - Rust: return a generic struct from a function where (only) <T> is different
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM