[英]How can I return None when a given enum is not a certain variant?
我定義了以下枚舉:
#[derive(Debug, Copy, Clone)]
struct Core;
#[derive(Debug, Copy, Clone)]
struct Mem;
#[derive(Debug, Copy, Clone)]
pub enum Atag {
Core(Core),
Mem(Mem),
Cmd(&'static str),
Unknown(u32),
None,
}
我想在這個enum上實現一個“過濾掉”某些枚舉值的函數。 我有以下內容:
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<Core> {
match self {
Atag::Core => Some(self),
_ => None
}
}
}
我不知道為什么,但編譯器抱怨:
error[E0532]: expected unit struct/variant or constant, found tuple variant `Atag::Core`
--> src/main.rs:17:13
|
17 | Atag::Core => Some(self),
| ^^^^^^^^^^ not a unit struct/variant or constant
help: possible better candidate is found in another module, you can import it into scope
|
1 | use Core;
|
我也嘗試了一種比較方法:
pub fn core(self) -> Option<Core> {
if self == Atag::Core {
Some(self)
} else {
None
}
}
但編譯器抱怨:
error[E0369]: binary operation `==` cannot be applied to type `Atag`
--> src/main.rs:20:12
|
20 | if self == Atag::Core {
| ^^^^^^^^^^^^^^^^^^
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `Atag`
我認為這只是模式匹配的限制,旨在防止意外行為。
具有Core
類型的Atag
的完整“定義”是Atag::Core(raw::Core)
。 顯然, Core
的內容與您無關,但編譯器需要知道所有內容都“被占用”,因為編譯器是規則的堅持者。 解決這個問題的最簡單方法是使用“任何模式”, _
,就像你匹配非Core
變體一樣。
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<Core> {
match self {
// The compiler now knows that a value is expected,
// but isn't necessary for the purposes of our program.
Atag::Core(_) => Some(self),
_ => None
}
}
}
要忽略多個值,您可以使用Something::Foo(_, _)
- 變量中的每個值使用一個下划線,或者忽略所有內容的Something::Foo(..)
。
請記住,與其他語言不同,Rust枚舉不僅僅是“不僅僅是”不同類型的集合。 與枚舉值相關聯的數據是其中的一部分,就像結構的字段一樣。 所以self == Atag::Core
不是一個有意義的語句,因為它忽略了與Core
相關的數據。 Foo(0)
與Foo(12)
,即使它們都是Foo
變體。
我還想指出, if let
- 就我所知 - 是最接近標准if
語句的選項而沒有在Atag
上定義一個自定義的is_core
函數(假設存在match
, if let
,則是基本上沒必要)。
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<Core> {
if let Atag::Core(_) = self {
Some(self)
} else {
None
}
}
}
我需要這樣的東西來很好地將函數鏈接在一起。 在這種情況下,您希望返回未包裝的核心類型,而不僅僅是枚舉。
我還發現不使用輸入更容易,因此接受了一個&self
參數並返回了一個Option<&Core>
。 但你可以同時擁有兩者。
Rust約定將as_X
作為基於引用的轉換,將into_X
作為消耗該值的轉換。 例如:
impl Atag {
fn as_core(&self) -> Option<&Core> {
if let Atag::Core(ref v) = self {
Some(v)
} else {
None
}
}
fn into_core(self) -> Option<Core> {
if let Atag::Core(v) = self {
Some(v)
} else {
None
}
}
}
fn main() {
let c = Atag::Core(Core {});
let m = Atag::Mem(Mem {});
assert_eq!(c.as_core().map(|cc| "CORE_REF"), Some("CORE_REF"));
assert_eq!(m.as_core().map(|cc| "CORE_REF"), None);
// Consume c - we cant use it after here...
assert_eq!(c.into_core().map(|cc| "NOM NOM CORE"), Some("NOM NOM CORE"));
// Consume m - we cant use it after here...
assert_eq!(m.into_core().map(|cc| "NOM NOM CORE"), None);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.