簡體   English   中英

使用Option創建通用結構 <T> 無實例化時不指定T

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

我有一個

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

嘗試使用b: None實例化結構時b: None編譯器抱怨它無法推斷類型,並且需要類型提示,例如通過turbofish語法。 這對調用者來說是很麻煩的,因為他們將不得不找到一個滿足特征范圍的類型並導入它,盡管它並不關心該可選功能。

我認為我正在尋找的是底部類型,該類型可以自動滿足任何特征范圍,但是無法實例化,因此可以使用None::<Bottom> ,但是我在文檔中沒有找到這種類型。

作品中有一個功能 ,可以將永不類型指定為! 在穩定的Rust中不存在此功能,因此您需要使用每晚和功能標記:

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

您可以在類似Hyper的板條箱中看到這種類似的模式,盡管它裝箱了具體的類型,所以您不會從外面看到它。

避免對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 };
}

為了簡單起見,我使用()作為默認值,但是! (如果有)或@Shepmaster的答案中您自己的底部類型可能更好。

如果您不介意Foo::new_default(i)或類似的函數,則構造函數也可以工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM