簡體   English   中英

當給定的枚舉不是某種變體時,如何返回None?

[英]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函數(假設存在matchif 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.

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