gpt4 book ai didi

rust - 同一 ARM 上不同类型的模式匹配

转载 作者:行者123 更新时间:2023-11-29 08:34:28 24 4
gpt4 key购买 nike

我想知道当两个或多个不同的枚举类型具有相同的数据成员或相同的函数时,是否有一种方法可以简化以下模式匹配臂。

(如果不是,最好解释原因)

更新:

作为我想要的更准确的示例(请原谅我将数据成员访问与函数混淆)(try it online):

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 有不同的实现,但我认为编译器足够聪明处理这个(我错了吗?)

尝试使用注释掉的代码进行编译会导致编译错误 (try it online):

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 上实现特征并委托(delegate)给内部类型可能会很方便.如果您没有特征,但您的类型具有共同的结构(如更新后的结构中的 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();

关于rust - 同一 ARM 上不同类型的模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53802119/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com