我有一个
struct Foo<T>
where
T: // ... some complex trait bound ...
{
a: Bar,
b: Option<T>,
}
当尝试使用b: None
实例化结构时,编译器会抱怨它无法推断出类型并需要类型提示,例如通过turbofish语法。这对调用者来说是繁重的,因为他们必须找到一个满足特征界限的类型并导入它,尽管不关心这个可选功能。
我认为我正在寻找的是底部类型,它会自动满足任何特征界限但无法实例化以便None::<Bottom>
可以使用,但我在文档中没有找到这样的类型。
答案 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的答案可能更好。
如果你不介意!
或类似的话,构造函数也可以工作。