簡體   English   中英

同一手臂上不同類型的圖案匹配

[英]Pattern matching on same arm with different types

我想知道當兩個或多個不同的枚舉類型具有相同的數據成員或相同的功能時,是否有一種方法可以簡化以下模式匹配臂。

(如果沒有,那么解釋原因將是很不錯的)

更新:

根據要求提供了我想要的更准確的示例(請原諒我將數據成員訪問與功能混淆)( 在線嘗試 ):

struct Point<T> {
    x: i32,
    y: T,
}

enum Record {
    V4(Point<i64>),
    V6(Point<i32>),
}

fn get_record() -> Record {
    Record::V4(Point{ x: 1, y: 1})
}

fn main() {
    let x = match get_record() {
        Record::V4(r) => r.x,
        Record::V6(r) => r.x,
    };
    println!("{}", &x);

    // this will not compile
    // let rec = get_record();
    // println!("{}", rec.x);

    // this will not compile either
    // note: if V4 Point was i32 it will compile & run
    // let rec = get_record();
    // let x = match get_record() {
    //     Record::V4(r) | Record::V6(r) => r.x,
    // };
}

原始帖子:

use std::net::IpAddr;
use std::str::FromStr;

fn main() {
    let v4_or_v6 = IpAddr::from_str("1.2.3.4").unwrap();

    // match expression, both arms only differ by 1 char
    let s = match v4_or_v6 {
        IpAddr::V4(ip) => ip.to_string(),
        IpAddr::V6(ip) => ip.to_string(),
    };
    println!("{}", &s);

    // not working:
    // let s2 = match v4_or_v6 {
    //     IpAddr::V4(ip) | IpAddr::V6(ip) => ip.to_string(),
    // };
    // println!("{}", &s2);
}

據我所知,底層調用to_string()有不同的實現Ipv4Ipv6 ,但我認為編譯器可以足夠聰明,處理這個(我錯了?)

嘗試使用注釋掉的代碼進行編譯會導致編譯錯誤( 在線嘗試 ):

Compiling playground v0.0.1 (/playground)

error[E0308]: mismatched types
  --> src/main.rs:16:37
   |
16 |         IpAddr::V4(ip) | IpAddr::V6(ip) => ip.to_string(),
   |                                     ^^ expected struct `std::net::Ipv4Addr`, found struct `std::net::Ipv6Addr`
   |
   = note: expected type `std::net::Ipv4Addr`
              found type `std::net::Ipv6Addr`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `playground`.

工作代碼將糖分解為:

let s = match v4_or_v6 {
    IpAddr::V4(ip) => <Ipv4Addr as ToString>::to_string(&ip),
    IpAddr::V6(ip) => <Ipv6Addr as ToString>::to_string(&ip),
};

即使語句看起來相同,它們的功能也不同,並且在每個分支中,靜態知道要使用哪個to_string 為了使它在單個匹配臂中起作用,您將必須以某種方式從模式匹配中生成一個特征對象,以便每個ip具有相同的類型(即&dyn ToString )。 目前尚無辦法,而且我還沒有看到任何類似的建議。

看到外觀相同的匹配臂是很常見的,甚至在rustc項目中,每個調用相同的特征方法。 暫時就是這樣。


如果您有一個enum ,每個變量都包含實現相同特征的類型,則可以方便地在enum上實現特征並將其委托給內部類型。 如果您沒有特征,但是您的類型具有共同的結構(如更新后的文章結構中的xy字段),則可以在enum提供訪問器:

impl Record {
    fn x(&self) -> i32 {
        match self {
            Record::V4(Point { x, .. }) => *x,
            Record::V6(Point { x, .. }) => *x,
        }
    }
}

雖然這基本上是同一回事,但是這意味着您只需編寫一次即可,而不必在需要訪問x的所有位置進行編寫:

let rec = get_record();
let x = get_record().x();

請注意, IpAddr已經做到了,因此,在您的原始代碼中,您可以完全避免match

let s = v4_or_v6.to_string();

暫無
暫無

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

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