[英]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.