2311rust模式匹配
原文
在Rust中混合匹配,改变和移动
结构模式匹配:极大的改进了C或Java风格的switch语句.
Match包含命令式和函数式编程风格:可继续使用break语句,赋值等,不必面向表达式.
按需匹配"借用"或"移动",:Rust鼓励开发者仔细考虑所有权和借用.设计匹配时仅支持借用子结构(而不是总移动).
基本匹配
Rust中的match(匹配)式有以下形式:
match INPUT_EXPRESSION {PATTERNS_1 => RESULT_EXPRESSION_1,PATTERNS_2 => RESULT_EXPRESSION_2,...PATTERNS_n => RESULT_EXPRESSION_n
}
其中每个PATTERNS_i至少包含一个模式.模式描述了INPUT_EXPRESSION可计算到的可能值的子集.语法PATTERNS=>RESULT_EXPRESSION叫"匹配分支",或简叫"分支".
模式可匹配如整数或符等简单值;还可通过枚举定义匹配用户定义的符号数据.
示例:
enum Answer {Higher,Lower,Bingo,
}
fn suggest_guess(prior_guess: u32, answer: Answer) {match answer {Answer::Higher => println!("maybe try {} next", prior_guess + 10),Answer::Lower => println!("maybe try {} next", prior_guess - 1),Answer::Bingo => println!("we won with {}!", prior_guess),}
}
#[test]
fn demo_suggest_guess() {suggest_guess(10, Answer::Higher);suggest_guess(20, Answer::Lower);suggest_guess(19, Answer::Bingo);
}
模式还可用(如元组,切片,结构)相应模式匹配结构化数据.绑定部分输入到局部变量;然后,可在结果式中使用这些变量.
struct GuessState {guess: u32,answer: Answer,low: u32,high: u32,
}
fn suggest_guess_smarter(s: GuessState) {match s {GuessState { answer: Answer::Bingo, guess: p, .. } => {
//..匹配值序列或名值对println!("we won with {}!", p);}GuessState { answer: Answer::Higher, low: _, guess: l, high: h } |GuessState { answer: Answer::Lower, low: l, guess: h, high: _ } => {
//_匹配单值,作为最后的默认.
//|表示`或者`.let mid = l + ((h - l) / 2);println!("lets try {} next", mid);}}
}
#[test]
fn demo_guess_state() {suggest_guess_smarter(GuessState {guess: 20, answer: Answer::Lower, low: 10, high: 1000});
}
编译时拒绝以下代码.
fn suggest_guess_broken(prior_guess: u32, answer: Answer) {let next_guess = match answer {Answer::Higher => prior_guess + 10,Answer::Lower => prior_guess - 1,//错误:未完整匹配.};println!("maybe try {} next", next_guess);
}
修复
fn suggest_guess_fixed(prior_guess: u32, answer: Answer) {let next_guess = match answer {Answer::Higher => prior_guess + 10,Answer::Lower => prior_guess - 1,Answer::Bingo => {println!("we won with {}!", prior_guess);return;}//补上最后分支};println!("maybe try {} next", next_guess);
}
#[test]
fn demo_guess_fixed() {suggest_guess_fixed(10, Answer::Higher);suggest_guess_fixed(20, Answer::Lower);suggest_guess_fixed(19, Answer::Bingo);
}
代数数据类型和结构不变量
代数数据类型简要描述了数据类,并允许丰富的结构不变量.
在Rust中,枚举可定义更加丰富的数据类.
如,二叉树或为叶,或为引用两个子树的内部节点.构建树:
enum BinaryTree {Leaf(i32),Node(Box<BinaryTree>, i32, Box<BinaryTree>)
}
Box<V>描述了拥有堆分配的V实例引用;如果拥有Box<V>,则也就拥有了它所包含的V,且可改变它,借出引用等等.
完成Box并出域时,自动清理与堆分配的V实例关联的资源.
上面的枚举定义确保,如果得到一个BinaryTree,将总是属于上述二者之一.永远不会遇见无左子的BinaryTree::Node.因此无需检查null.
但确实要检查给定的BinaryTree是Leaf还是Node,但编译器会静态确保此类检查:你不会意外地按节点解释Leaf数据,反之亦然.
如下使用match对树中的所有整数求和:
fn tree_weight_v1(t: BinaryTree) -> i32 {match t {BinaryTree::Leaf(payload) => payload,BinaryTree::Node(left, payload, right) => {tree_weight_v1(*left) + payload + tree_weight_v1(*right)}}
}///返回如下的树:
/// +----(4)---+
/// | |
/// +-(2)-+ [5]
/// | |
/// [1] [3]
fn sample_tree() -> BinaryTree {let l1 = Box::new(BinaryTree::Leaf(1));let l3 = Box::new(BinaryTree::Leaf(3));let n2 = Box::new(BinaryTree::Node(l1, 2, l3));let l5 = Box::new(BinaryTree::Leaf(5));BinaryTree::Node(n2, 4, l5)
}
#[test]
fn tree_demo_1() {let tree = sample_tree();assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5);
}
代数数据类型创建语言严格执行的结构不变量.
既面向表达式,也面向语句
下面的代码使用区间模式来简化,编写风格类似面向语句语言(如C(或C++,Java等)中的开关(switch)),其中仅针对该分支执行匹配:
fn num_to_ordinal(x: u32) -> String {let suffix;match (x % 10, x % 100) {(1, 1) | (1, 21...91) => {suffix = "st";}(2, 2) | (2, 22...92) => {suffix = "nd";}(3, 3) | (3, 23...93) => {suffix = "rd";}_ => {suffix = "th";}}return format!("{}{}", x, suffix);
}
#[test]
fn test_num_to_ordinal() {assert_eq!(num_to_ordinal( 0), "0th");assert_eq!(num_to_ordinal( 1), "1st");assert_eq!(num_to_ordinal( 12), "12th");assert_eq!(num_to_ordinal( 22), "22nd");assert_eq!(num_to_ordinal( 43), "43rd");assert_eq!(num_to_ordinal( 67), "67th");assert_eq!(num_to_ordinal(1901), "1901st");
}
静态分析确保:
1,总是在在函数尾,格式!之前初化后缀.
2,执行函数时,最多分配一次后缀.(如果是多次,编译器会提醒你),
面向表达式,则如下:
fn num_to_ordinal_expr(x: u32) -> String {format!("{}{}", x, match (x % 10, x % 100) {(1, 1) | (1, 21...91) => "st",(2, 2) | (2, 22...92) => "nd",(3, 3) | (3, 23...93) => "rd",_ => "th"})
}
想要初化某个状态,然后借用它时,但仅限于某些控制流分支.
fn sometimes_initialize(input: i32) {let string: String; //动态构造串值let borrowed: &str; //引用串数据match input {0...100 => {//临时构造串...string = format!("input prints as {}", input);//...然后从中借用.borrowed = &string[6..];}_ => {//串字面是*已*借用的引用borrowed = "期望0 and 100间";}}println!("borrowed: {}", borrowed);//println!("string: {}", string);//取消上面注释,会报错.借用已借用了串,你不能再用了.
}
#[test]
fn demo_sometimes_initialize() {sometimes_initialize(23); //此调用初化"串`"`,sometimes_initialize(123); //此调用不会
}
有趣在,匹配后,禁止直接访问串,因为在访问前,必须在每个路径上初化变量.
但,可用borrowed访问串中数据,因为确保已初化了该串.
编译器确保借用的串数据不会超过串自身,且生成代码确保在串域尾,如果已初化它,则会释放它.
总之,为了健壮性,Rust语言确保在引用数据前,总是初化它.
匹配而不移动
匹配输入可不取所有权,直接借用输入;对匹配引用(如&T)至关重要.
上面版本的tree_weight有个很大的缺点:它按值取输入树.一旦传递一棵树给tree_weight_v1,这棵树就消失了(如,释放).
#[test]
fn tree_demo_v1_fails() {let tree = sample_tree();assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5);//assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5);//取消注释,会报错.
}
然而,这不是匹配造成的;而是函数签名:
fn tree_weight_v1(t: BinaryTree) -> i32 { 0 }
//即此函数拥有了`'t'`的所有权
在Rust中,匹配不取所有权,也良好运行.即,要匹配的输入是左值式.
匹配,执行此求值,然后检查该内存位置的数据.
(如果输入式是变量名或字段/指针解引用,则左值只是该变量或字段/内存的位置.如果输入式是生成未命名临时值的函数调用或其他操作,则存储在匹配检查的临时区域(内存位置)中.)
因此,如果仅想借用一棵树而不拥有它的tree_weight版本,则需要利用Rust匹配的该特性.
fn tree_weight_v2(t: &BinaryTree) -> i32 {//表示正在*借用*树,&表示借用.match *t {//解引用BinaryTree::Leaf(payload) => payload,BinaryTree::Node(ref left, payload, ref right) => {//引用分支的引用绑定.tree_weight_v2(left) + payload + tree_weight_v2(right)}}
}
#[test]
fn tree_demo_2() {let tree = sample_tree();assert_eq!(tree_weight_v2(&tree), (1 + 2 + 3) + 4 + 5);
}
该tree_weight_v2函数非常像tree_weight_v1.唯一的区别是:t是借用的引用(用&),并添加了*t解引用,重要的是,对Node的left和right使用引用绑定.
(按左值式)解引用*t,只是取表示BinaryTree的内存地址(因为t:&BinaryTree只是引用内存中的该数据).
*t不是复制树,也不是移动到新的临时位置,因为match按左值对待它.
引用绑定
首先,非引用绑定的含义:
匹配T类型值时,在成功匹配时,i标识模式把值从原始输入移出并移入i.因此,此时,i有T型(或"i:T").
对可复制T(实现Copy的T),该模式绑定表明i变量拥有T类型值的所有权.
因此,tree_weight_v2中负载的绑定都有i32类型;i32类型实现了Copy,因此把权重复制到两个分支的负载中.
而引用绑定:
匹配T类型左值时,在成功匹配时,引用绑定(ref i),只会借用匹配数据的引用.即,成功匹配T类型值的ref i表明i借用T的引用(即,"i:&T").
因此,在tree_weight_v2的Node分支中,left,引用(包含一棵树的)左边树,而right则引用右边树.
在递归调用tree_weight_v2中,可传递这些引用.
同样,在成功匹配时,可变引用借用输入的可变引用:即i:&mut T.这允许改变,并确保同时无其他活动的该数据引用.
match的此解构绑定形式,允许你同时取数据的不相交部分的可变引用.
如下递增给定树中的所有值.
fn tree_grow(t: &mut BinaryTree) {//mut':独占权match *t {BinaryTree::Leaf(ref mut payload) => *payload += 1,BinaryTree::Node(ref mut left, ref mut payload, ref mut right) => {tree_grow(left);//加左*payload += 1;tree_grow(right);//加右}}
}
#[test]
fn tree_demo_3() {let mut tree = sample_tree();tree_grow(&mut tree);assert_eq!(tree_weight_v2(&tree), (2 + 3 + 4) + 5 + 6);
}
注意,现在通过可变引用绑定有效负载;如果不用引用,则负载绑定到整数的本地副本,但想修改树自身中实际整数.就需要用该整数的引用.
注意,代码可在Node分支中,可同时绑定左右.编译器知道这两个值不是别名,因此允许同时存在两个&mut引用.
更多:
1,在模式中,如何用Higher而不是Answer::Higher,
2,定义新的命名常量,
3,通过ident @ pattern绑定
4,
{ let id = expr; ... }
//与如下的区别:
match expr { id => { ... } }
相关文章:
2311rust模式匹配
原文 在Rust中混合匹配,改变和移动 结构模式匹配:极大的改进了C或Java风格的switch语句. Match包含命令式和函数式编程风格:可继续使用break语句,赋值等,不必面向表达式. 按需匹配"借用"或"移动",:Rust鼓励开发者仔细考虑所有权和借用.设计匹配时仅支持…...
Linux系统软件安装方式
Linux系统软件安装方式 1. 绿色安装2. yum安装3. rpm安装3.1 rpm常用命令 4. 源码安装4.1 安装依赖包4.2 执行configure脚本4.3 编译、安装4.4 安装4.5 操作nginx4.6 创建服务器 1. 绿色安装 Compressed Archive压缩文档包,如Java软件的压缩文档包,只需…...
React + Antd 自定义Select选择框 全选、清空功能
实现代码 import React, { useState, useEffect } from react; import { Select, Space, Divider, Button } from antd;export default function AllSelect (props) {const {fieldNames, // 自定义节点labbel、value、options、grouLabeloptions, // 数据化配置选项内容&#…...
阿里云国际站:应用实时监控服务
文章目录 一、阿里云应用实时监控服务的概念 二、阿里云应用实时监控服务的优势 三、阿里云应用实时监控服务的功能 四、写在最后 一、阿里云应用实时监控服务的概念 应用实时监控服务 (Application Real-Time Monitoring Service) 作为一款云原生可观测产品平台ÿ…...
专题知识点-二叉树-(非常有意义的一篇文章)
这里写目录标题 二叉树的基础知识知识点一(二叉树性质 )树与二叉树的相互转换二叉树的遍历层次优先遍历树的深度和广度优先遍历中序线索二叉树二叉树相关遍历代码顺序存储和链式存储二叉树的遍历二叉树的相关例题左右两边表达式求值求树的深度找数找第k个数二叉树非递归遍历代码…...
多路数据写入DDR3/DDR4的两种方法
1.官方IP实现; 2.手写Axi 仲裁器。...
3 分钟看完 NVIDIA GPU 架构及演进
近期随着 AI 市场的爆发式增长,作为 AI 背后技术的核心之一 GPU(图形处理器)的价格也水涨船高。GPU 在人工智能中发挥着巨大的重要,特别是在计算和数据处理方面。目前生产 GPU 主流厂商其实并不多,主要就是 NVIDIA、AM…...
SMART PLC 和S7-1200PLC MODBUSTCP通信速度测试
SMART PLC MODBUSTCP通信详细介绍请参看下面文章链接: S7-200SMART PLC ModbusTCP通信(多服务器多从站轮询)_matlab sumilink 多个modbustcp读写_RXXW_Dor的博客-CSDN博客文章浏览阅读6.4k次,点赞5次,收藏10次。MBUS_CLIENT作为MODBUS TCP客户端通过S7-200 SMART CPU上的…...
C++文件操作知识点总结
文件流操作文本文件 文件流 在 C 中,对文件的操作是通过 stream 的子类 fstream( file stream )来实现的,所以,要用这种方式操作文件,就必须加入头文件<fstream>,代码如下: …...
开发vue3 UI组件库,并且发布到NPM
目录 1.创建vue3工程 2.创建package文件 3.编写组件,并且导出 4.编写package.json 5.npm账号注册登录并发布 6.从npm安装使用 7.注意事项 1.创建vue3工程 (1)初始化Vue项目 cnpm create vite (2)进入文件夹…...
雷达测角原理、测角精度、测角分辨率以及3DFFT角度估计算法汇总
1.角度测量方法 依据:电磁波的直线传播和雷达天线的方向性。 分类:振幅法测角、相位法测角 1.1 相位法测角 相位法测角利用多个天线所接收回波信号之间的相位差进行测角。如下图所示; 图 1 设在θ方向有一远区目标,则到达接收点…...
金财数科无代码开发平台:轻松实现电商、CRM、广告推广系统的集成连接
连接与集成:挖掘电商平台的潜力 金财数科是一家领先的信息技术公司,专注于利用前沿技术如互联网、人工智能、大数据和区块链等,为传统财税信息化方案和产品提供升级改造,并打造新一代智能财税SaaS平台。我们的目标是帮助企业通过…...
JavaWeb篇_09——Tomcat运行过程以及Servlet继承结构
Tomcat运行过程 用户访问localhost:8888/test/helloword.do,请求被发送到Tomcat,被监听8888端口并处理 HTTP/1.1 协议的Connector获得。Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。Engine获得请求localhost/t…...
Python中的异常与错误处理
一、基础知识 1、一个try语句支持多个except子句,但请记得将更精确的异常类型放在前面。 2、try语句的else分支会在没有异常时执行,因此它可以用来替代标记变量(flag变量)。 3、不带任何参数的raise语句会直接重复抛出当前异常。…...
sqli-labs关卡16(基于post提交的双引号加括号闭合的布尔盲注)通关思路
文章目录 前言一、回顾上一关知识点二、靶场第十六关通关思路1、判断注入点2、猜数据库长度3、猜数据库名字4、猜表名长度5、猜表名名字6、猜列名长度7、猜列名名字8、猜数据长度9、猜数据名字 总结 前言 此文章只用于学习和反思巩固sql注入知识,禁止用于做非法攻击…...
2.5k的ChatGPT-Java版SDK升级1.1.2-beta0支持GPT-4V、Dall-e-3模型、ToolCalls、微调Job、TTS...
1、项目简介 Chatgpt-Java是OpenAI官方Api的Java SDK,可以快速接入项目使用。支持OpenAI官方全部接口。 目前收获将2500star🌟。 开源地址:https://github.com/Grt1228/chatgpt-java官方文档:https://chatgpt-java.unfbx.com/最…...
k8s二进制(ETCD的部署安装)
角色ip组件k8s-master192.168.11.169kube-apiserver,kube-controller-manager,kube-scheduler,etcdk8s-node1192.168.11.164kubelet,kube-proxy,docker,etcdk8s-node2192.168.11.166kubelet,kube-proxy,docker,etcd 1、为etcd签发证书 1、证书的下载(任意机器上执行都可以) …...
【rl-agents代码学习】02——DQN算法
文章目录 Highway-env Intersectionrl-agents之DQN*Implemented variants*:*References*:Query agent for actions sequence探索策略神经网络实现小结1 Record the experienceReplaybuffercompute_bellman_residualstep_optimizerupdate_target_network小结2 exploration_polic…...
关于使用 Java 反射技术来实现解耦?
关于使用 Java 反射技术来实现解耦? 文章目录 关于使用 Java 反射技术来实现解耦?一、基本说明二、代码示例三、注意 一、基本说明 Java 反射技术允许程序在运行时加载、探索和使用类和对象。通过反射,我们可以在程序运行期间动态地创建对象…...
使用清华智谱ChatGLM2大模型搭建本地私有知识库
首先放上该方案项目的git地址:https://github.com/chatchat-space/Langchain-Chatchat 以下是我的搭建和踩坑经验记录 一、环境准备 1、python安装 在环境中安装python,我安装的是3.9版本的python,官方要求的是Python 3.8 - 3.10 版本。不知…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
