同一手臂上不同类型的模式匹配

2024-01-29

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

(如果没有,最好解释一下原因)

UPDATE:

根据要求提供我想要的更准确的示例(请原谅我将数据成员访问与函数混淆)():

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()有不同的实现Ipv4 than Ipv6但我认为编译器可以足够聪明来处理这个问题(我错了吗?)

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

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并委托给内部类型。如果你没有特征,但你的类型有共同的结构(如x, y更新后的帖子结构中的字段),那么您可以在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();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

同一手臂上不同类型的模式匹配 的相关文章

随机推荐

  • 为什么 PHP Composer 这么慢?

    Why is PHP 作曲家 https en wikipedia org wiki Composer software 当我所做的只是初始化一个零依赖项的项目时 速度这么慢 以下是我运行的命令 composer init composer
  • 为什么闭包比全局变量更能保存变量?

    我了解闭包在 JavaScript 中的工作原理 但我的问题是为什么要费尽心思创建闭包来保存变量 不能把变量设为全局吗 或者这会扰乱全局范围并使您的代码容易出错 这是一个范围界定问题 全局变量就是这样 Global toeveryone 使
  • 我应该如何安装keras-bert才能在R端正确使用?

    我正在尝试按照解释安装 keras berthere https blogs rstudio com ai posts 2019 09 30 bert r 虽然它已成功安装在环境 as 上 但我在 R 端看不到 keras bert ber
  • Kafka 事务失败但仍提交偏移量

    我正在尝试了解 Kafka 事务和一次性事务 我创建了一个事务消费者 我想确保我读取并处理某个主题的所有消息 如果事务失败并且消息因此丢失 Kafka 仍会提交偏移量 更正式地说 如果流处理应用程序消费消息 A 并生成消息 B 使得 B F
  • 如何将重音字符与 PHP preg 匹配?

    我想让我的用户不仅可以选择填写字母和数字 还可以选择 特殊 字母 例如 等 但是 我不希望他们能够使用符号如 等 有没有办法编写正则表达式来完成此任务 最好不要指定每个特殊字母 我现在有 reg w 你可以使用Unicode 字符属性 ht
  • networkx 有向图属性错误 self._succ

    Context 我正在尝试运行另一位研究人员的代码 它描述了湾区道路网络的交通模型 该模型容易受到地震灾害的影响 我是 Python 新手 因此非常感谢您帮助调试以下错误 Issue 当我尝试按照文件中提供的示例数据运行代码时 按照自述文件
  • Membership.DeleteUser 未删除用户的所有相关行

    Membership DeleteUser 设法删除我要删除的用户的用户配置文件 为什么它不删除它存储在的信息webpages membership 我目前没有使用角色 因此请记住这一点以获取答案 我进行了测试并验证了这一点SimpleMe
  • 可重用预处理器 __COUNTER__

    我正在做一些模板元编程 主要是编写我自己的编译时间列表 但我也有一些预处理器魔法 我想用它们来使事情变得更容易 如果可能的话 我想做的是创建一个函子的编译时列表 该部分已完成 但用于简化创建 并添加到列表中 的宏尚未完成 简单举个例子 te
  • 如何实现Web应用程序的屏幕共享? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 Prologue 我想问 如何创建在网络上共享桌面屏幕的解决方案 但后来发现有很多这样的问题 这个任务非常复杂 无法用几个字符串来回答
  • 如何防止我的 .Net dll 被添加为引用?

    假设我编写了一个 Net dll 并希望将其与我的应用程序一起分发 我怎样才能防止任何有能力安装 VS 副本的用户向自己的应用程序添加对此 dll 的引用 无法阻止用户添加引用 这是 DLL 部分的被动操作 您无法采取任何措施来阻止它发生
  • 如果不存在则创建

    我有一个 Django 应用程序 它从 Web API 读取数据并将其放入数据库中 有没有办法从模式创建新对象 但如果对象已经存在 则可以防止重复异常 换句话说 有没有办法保存一个对象 但如果它已经存在则什么都不做 Model object
  • 通过 Powershell 在 IIS 7.5 中启用模拟

    我希望有人可以提供帮助 我正在尝试在 IIS 7 的身份验证会话下启用 ASP Net 模拟 我已使用以下命令启用了其他部分 Set WebConfigurationProperty filter system WebServer secu
  • 在 Perl 中启动非等待后台进程

    我有一个 Perl 脚本 需要在后台启动另一个进程并退出 而不等待其他脚本完成 StackOverflow 上有很多线程介绍如何在 Perl 中等待或如何不等待其他编程语言 但我似乎找不到 Perl 的正确答案 我已经阅读了相当多的内容 并
  • 为什么 foreach %dopar% 每增加一个节点就会变慢?

    我编写了一个简单的矩阵乘法来测试网络的多线程 并行化功能 我注意到计算速度比预期慢得多 The Test很简单 乘以 2 个矩阵 4096x4096 并返回计算时间 矩阵和结果都不被存储 计算时间并非微不足道 50 90 秒 具体取决于您的
  • 如何向枚举添加多个属性?

    我有一个名为的 SQL 查找表客户信用解决计划行动类型我想转换为enum questions tagged enum in c questions tagged c 23 非常基本的要求 对吧 正确的 我的桌子 现在enum questio
  • co_await 似乎不是最理想的?

    我有一个异步函数 void async foo A a B b C c function
  • IE11框架通知栏保存按钮

    在装有 MS Excel 2010 和 IE11 的 64 位系统上 我使用此代码自动从网站下载过程 hWnd FindWindowEx IE hWnd 0 Frame Notification Bar vbNullString If hW
  • 如何将文件读入整数数组

    在我的应用程序文档文件夹中 我有一个文件 我试图将其逐字节读入数组UInt8其中每个元素代表一个字节 我该怎么做呢 该文件恰好名为 Q1 dat 这是我不成功的尝试 func readArray gt Int if let arrayPat
  • 使用 angular2 显示/隐藏密码文本

    我想根据用户点击显示 隐藏密码文本 但我收到以下错误消息 export class App password secret show false ContentChild ShowHideInput input ShowHideInput
  • 同一手臂上不同类型的模式匹配

    我想知道当两个或多个不同的枚举类型具有相同的数据成员或相同的函数时 是否有一种方法可以简化以下模式匹配臂 如果没有 最好解释一下原因 UPDATE 根据要求提供我想要的更准确的示例 请原谅我将数据成员访问与函数混淆 struct Point