Pattern matching on same arm with different types

后端 未结 1 530
栀梦
栀梦 2021-01-17 06:11

I wonder if there is a way to simplify the following pattern match arms when two or more different enum\'s types have the same data member or same function.

(if not

相关标签:
1条回答
  • 2021-01-17 06:48

    The working code de-sugars to:

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

    Even though the statements look the same, they are different functions and in each branch it is known statically which to_string is going to be used. To get this to work in a single match arm, you would have to somehow produce a trait object from the pattern match, so that each ip has the same type (i.e. &dyn ToString). Currently there isn't a way to do that and I haven't seen any proposal like it.

    It's pretty common to see identical-looking match arms, where the same trait method is called on each, even in the rustc project. This is just how it is, for now.


    If you have an enum where each variant holds types that implement the same traits, it might be convenient to implement the traits on the enum and delegate to the inner types. If you don't have a trait but your types have common structure (as in the x, y fields in the struct of your updated post), then you can provide an accessor on the enum:

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

    While this is basically the same thing, it means you can write it once instead of everywhere that you need to access x:

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

    Note that IpAddr already does this so, in your original code, you could have avoided the match altogether with:

    let s = v4_or_v6.to_string();
    
    0 讨论(0)
提交回复
热议问题