当前位置: 首页 > news >正文

Rust模式匹配

模式匹配

模式匹配是从函数式编程语言(例如:Haskell,Lisp)吸收而来的,用于为复杂的类型系统提供一个轻松的解构能力。rust使用match来提供模式匹配的功能。mathc类似于其它编程语言中的switch-case,但是远比switch-case强大。match的通用模式如下所示。

match target {模式1 => 表达式1,模式2 => {语句1;语句2;表达式2},_ => 表达式3
}

该形式清晰的说明了何为模式,何为模式匹配:将模式与 target 进行匹配,即为模式匹配,而模式匹配不仅仅局限于 match,还有if let。一个实际的例子如下所示:

fn main() {enum Coin {Penny,Nickel,Dime,Quarter,}fn value_in_cents(coin: Coin) -> u8 {match coin {Coin::Penny =>  {println!("Lucky penny!");1},Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter => 25,}}let coin = Coin::Dime;let x = value_in_cents(coin);println!("{}", x);
}
  • match 的匹配必须要穷举出所有可能,因此这里用 _ 来代表未列出的所有可能性。当我们不想使用通配模式获取的值时,请使用 _ ,这是一个特殊的模式,可以匹配任意值而不绑定到该值。这告诉 Rust 我们不会使用这个值,所以 Rust 也不会警告我们存在未使用的变量。
  • match 的每一个分支都必须是一个表达式,且所有分支的表达式最终返回值的类型必须相同
  • match 的模式之间可以使用X | Y,类似逻辑或,代表该分支可以匹配 X 也可以匹配 Y,只要满足一个即可

match表达式在执行时,将目标值coin按照顺序依次与每一个分支的模式相比较,如果模式匹配了这个值,那么模式之后的代码将被执行。如果模式并不匹配这个值,将继续执行下一个分支。每个分支相关联的代码是一个表达式,而表达式的结果值将作为整个 match 表达式的返回值。如果分支有多行代码,那么需要用 {} 包裹,同时最后一行代码需要是一个表达式。

使用match表达式赋值

#![allow(unused)]
enum IpAddr {Ipv4,Ipv6
}fn main() {let ip1 = IpAddr::Ipv6;let ip_str = match ip1 {IpAddr::Ipv4 => "127.0.0.1",_ => "::1",};println!("{}", ip_str);
}

通过match表达式,给ip_str赋值(绑定)了一个Ipv6的地址::1(环回地址)。

模式匹配取出值

模式匹配的另外一个重要功能是从模式中取出绑定的值。例如:

enum Action {Say(String),MoveTo(i32, i32),ChangeColorRGB(u16, u16, u16),
}fn main() {let actions = [Action::Say("Hello Rust".to_string()),Action::MoveTo(1,2),Action::ChangeColorRGB(255,255,0),];for action in actions {match action {Action::Say(s) => {                 //当action匹配Action::Say的时候,s将会取出取出其中的值println!("{}", s);},Action::MoveTo(x, y) => {           // 也可以取出多个值println!("point from (0, 0) move to ({}, {})", x, y);},Action::ChangeColorRGB(r, g, _) => {println!("change color into '(r:{}, g:{}, b:0)', 'b' has been ignored",r, g,);}}}
}

运行后输出如下所示:

Hello Rust
point from (0, 0) move to (1, 2)    
change color into '(r:255, g:255, b:0)', 'b' has been ignored

通配符(_)

当我们不想在匹配时列出所有值的时候,可以使用 Rust 提供的一个特殊模式,例如,u8 可以拥有 0 到 255 的有效的值,但是我们只关心 1、3、5 和 7 这几个值,不想列出其它的 0、2、4、6、8、9 一直到 255 的值。例如:

let some_u8_value = 0u8;
match some_u8_value {1 => println!("one"),3 => println!("three"),5 => println!("five"),7 => println!("seven"),_ => (),
}

通过将 _ 其放置于其他分支后,_ 将会匹配所有遗漏的值。() 表示返回单元类型与所有分支返回值的类型相同(因为println!宏返回()),所以当匹配到 _ 后,什么也不会发生。

if let匹配

在某些场景下,我们其实只关心某一个值是否存在,此时 match 就显得过于啰嗦。例如:

let v = Some(3u8);match v {Some(3) => println!("three"),_ => (),}

我们只想要对 Some(3) 模式进行匹配, 不想处理任何其他 Some 值或 None 值。但是为了满足 match 表达式(穷尽性)的要求,写代码时必须在处理完这唯一的成员后加上 _ => (),这样会增加不少无用的代码。为此,rust提供了更加简洁的if-let匹配,上面的例子可以改写为如下所示:

if let Some(3) = v {println!("three");
}

matches!宏

Rust 标准库中提供了一个非常实用的宏:matches!,它可以将一个表达式跟模式进行匹配,然后返回匹配的结果 true or false。例如:

let foo = 'f';
assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));let bar = Some(4);
assert!(matches!(bar, Some(x) if x > 2));

解构Option

之前在枚举类型中,遗留的一个问题是:“一个变量要么有值:Some(T), 要么为空:None”。当时没有取出Some中的值,现在有了模式匹配,我们来实现取出值。例如:

let num = Some(123i32);
let num1: i32;
num1 = match num {Some(x) => x,None => 0,
};println!("{}", num1);

这个例子中,我们只是对数值类型做了取出操作,对其它类型也是类似的。例如:

let s = Some("123".to_string());
let s1:String;
s1 = match s {Some(x) => x,None => " ".to_string(),
};
println!("{}", s1);

只不过对于String这种存储在堆内存上的数据类型而言,这会导致所有权的转移,从而导致s在模式匹配之后无法使用。

模式匹配无处不在

在rust中,模式匹配无处不在。除了match,if-let之外。还有while let, for循环,let语句,函数参数等都是模式匹配。

while let

while let条件循环,它的作用是只要模式匹配,循环就能一直进行。下面是一个例子。

// Vec是动态数组
let mut stack = Vec::new();// 向数组尾部插入元素
stack.push(1);
stack.push(2);
stack.push(3);// stack.pop从数组尾部弹出元素
while let Some(top) = stack.pop() {println!("{}", top);
}

pop 方法取出动态数组的最后一个元素并返回 Some(value),如果动态数组是空的,将返回 None。如果返回了None,那么while循环将会结束。

for循环

let v = vec!['a', 'b', 'c'];for (index, value) in v.iter().enumerate() {println!("{} is at index {}", value, index);
}

像这样的for循环,本质上也是模式匹配。迭代器每次迭代会返回一个 (索引,值) 形式的元组,然后用 (index,value) 来匹配。

let语句

实际上let x = 3,这也是一种模式绑定,代表将匹配的值绑定到变量 x 上。更复杂一些的比如元组。let (x, y, z) = (1, 2, 3)。因此,在 Rust 中变量名也是一种模式。

函数参数

fn print_coordinates(&(x, y): &(i32, i32)) {println!("Current location: ({}, {})", x, y);
}fn main() {let point = (3, 5);print_coordinates(&point);
}

在函数中,参数也是一种模式匹配。&(3, 5) 会匹配模式 &(x, y),因此 x 得到了 3,y 得到了 5。

可驳模式和不可驳模式

在rust中,模式匹配可以分为两类,一类是可驳模式,另一类是不可驳模式。像let, for, match这类属于不可驳模式匹配,它们要求必须完全覆盖匹配;而if-let, while-let这种属于可驳模式,它们允许忽略其余的模式。

通过…=匹配值的范围

let x = 3;match x {1..=3 => println!("one through three"),4..8 => println!("four through seven")_ => println!("something else"),
}

..= 语法允许你匹配一个闭区间序列内的值。序列只允许用于数字或字符类型,原因是:它们可以连续,同时编译器在编译期可以检查该序列是否为空,字符和数字值是 Rust 中仅有的可以用于判断是否为空的类型。

let x = 'c';match x {'a'..='j' => println!("early ASCII letter"),'k'..='z' => println!("late ASCII letter"),_ => println!("something else"),
}

Rust 知道 ‘c’ 位于第一个模式的序列内,所以会打印出 early ASCII letter。

解构结构体

struct Point {x: i32,y: i32,
}fn main() {let p = Point { x: 0, y: 7 };let Point { x: a, y: b } = p;assert_eq!(0, a);assert_eq!(7, b);
}

这段代码创建了变量 a 和 b 来匹配结构体 p 中的 x 和 y 字段,这个例子展示了模式中的变量名不必与结构体中的字段名一致。不过通常希望变量名与字段名一致以便于理解变量来自于哪些字段。这时候只需要将let Point { x: x, y: y } = p;简写为let Point { x, y } = p;即可。

也可以使用字面值作为结构体模式的一部分进行解构,而不是为所有的字段创建变量。这允许我们测试一些字段为特定值的同时创建其他字段的变量。

fn main() {let p = Point { x: 0, y: 7 };match p {Point { x, y: 0 } => println!("On the x axis at {}", x),Point { x: 0, y } => println!("On the y axis at {}", y),Point { x, y } => println!("On neither axis: ({}, {})", x, y),}
}

在这个例子中,首先是 match 第一个分支,指定匹配 y 为 0 的 Point; 然后第二个分支在第一个分支之后,匹配 y 不为 0,x 为 0 的 Point; 最后一个分支匹配 x 不为 0,y 也不为 0 的 Point。

解构枚举

enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}fn main() {let msg = Message::ChangeColor(0, 160, 255);match msg {Message::Quit => {println!("The Quit variant has no data to destructure.")}Message::Move { x, y } => {println!("Move in the x direction {} and in the y direction {}",x,y);}Message::Write(text) => println!("Text message: {}", text),Message::ChangeColor(r, g, b) => {println!("Change the color to red {}, green {}, and blue {}",r,g,b)}}
}

模式匹配一样要类型相同,因此匹配 Message::Move{1,2} 这样的枚举值,就必须要用 Message::Move{x,y} 这样的同类型模式才行。

这段代码会打印出 Change the color to red 0, green 160, and blue 255。尝试改变 msg 的值来观察其他分支代码的运行。

对于像 Message::Quit 这样没有任何数据的枚举成员,不能进一步解构其值。只能匹配其字面值 Message::Quit,因此模式中没有任何变量。

对于另外两个枚举成员,就用相同类型的模式去匹配出对应的值即可。

解构嵌套的结构体和枚举

#![allow(unused)]
enum Color {Rgb(i32, i32, i32),Hsv(i32, i32, i32),
}enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(Color),
}fn main() {let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));match msg {Message::ChangeColor(Color::Rgb(r, g, b)) => {println!("Change the color to red {}, green {}, and blue {}",r,g,b)}Message::ChangeColor(Color::Hsv(h, s, v)) => {println!("Change the color to hue {}, saturation {}, and value {}",h,s,v)}_ => ()}
}

模式匹配非常强大,像这样嵌套的结构体和枚举,它也能进行解构,取出嵌套在其中的值。下面是一个更复杂的例子:

#![allow(unused)]
fn main() {
struct Point {x: i32,y: i32,}let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 });
}

结构体和元组嵌套在元组中,rust依旧可以将这种复杂类型分解匹配,从而让我们取出感兴趣的值。

解构数组

对于数组,我们可以用类似元组的方式解构,分为两种情况:

  • 定长数组
let arr: [u16; 2] = [114, 514];
let [x, y] = arr;assert_eq!(x, 114);
assert_eq!(y, 514);
  • 不定长数组
let arr: &[u16] = &[114, 514];if let [x, ..] = arr {assert_eq!(x, &114);
}if let &[.., y] = arr {assert_eq!(y, 514);
}let arr: &[u16] = &[];assert!(matches!(arr, [..]));
assert!(!matches!(arr, [x, ..]));

..是用来忽略剩余值的,后续会介绍。

忽略模式中的值

有时忽略模式中的一些值是很有用的,比如在 match 中的最后一个分支使用 _ 模式匹配所有剩余的值。 你也可以在另一个模式中使用 _ 模式,使用一个以下划线开始的名称,或者使用 … 忽略所剩部分的值。

使用 _ 忽略整个值

虽然 _ 模式作为 match 表达式最后的分支特别有用,但是它的作用还不限于此。例如可以将其用于函数参数中:

fn foo(_: i32, y: i32) {println!("This code only uses the y parameter: {}", y);
}fn main() {foo(3, 4);
}

此时编译器就不会警告说存在未使用的函数参数,就跟使用命名参数一样。

使用嵌套的 _ 忽略部分值

let mut setting_value = Some(5);
let new_setting_value = Some(10);match (setting_value, new_setting_value) {(Some(_), Some(_)) => {println!("Can't overwrite an existing customized value");}_ => {setting_value = new_setting_value;}
}println!("setting is {:?}", setting_value);

第一个匹配分支,我们不关心里面的值,只关心元组中两个元素的类型,因此对于 Some 中的值,直接进行忽略。 剩下的形如 (Some(),None),(None, Some()), (None,None) 形式,都由第二个分支 _ 进行分配。还可以在一个模式中的多处使用下划线来忽略特定值,如下所示,这里忽略了一个五元元组中的第二和第四个值:

let numbers = (2, 4, 8, 16, 32);match numbers {(first, _, third, _, fifth) => {println!("Some numbers: {}, {}, {}", first, third, fifth)},
}

用 … 忽略剩余值

前文的不定长数组的模式中出现了..,用来忽略除开头以外的值,或者是除结尾以外的值。当然了,..也可以忽略中间的某些值。例如:

fn main() {let numbers = (2, 4, 8, 16, 32);match numbers {(first, .., last) => {println!("Some numbers: {}, {}", first, last);},}
}

这里用 first 和 last 来匹配第一个和最后一个值。… 将匹配并忽略中间的所有值。然而使用 … 必须是无歧义的。如果期望匹配和忽略的值是不明确的,Rust 会报错。下面代码展示了一个带有歧义的 … 例子,因此不能编译:

fn main() {let numbers = (2, 4, 8, 16, 32);match numbers {(.., second, ..) => {println!("Some numbers: {}", second)},}
}

Rust 无法判断,second 应该匹配 numbers 中的第几个元素,因此无法通过编译。

匹配守卫

匹配守卫(match guard)是一个位于 match 分支模式之后的额外 if 条件,它能为分支模式提供更进一步的匹配条件。
这个条件可以使用模式中创建的变量:

let num = Some(4);match num {Some(x) if x < 5 => println!("less than five: {}", x),Some(x) => println!("{}", x),None => (),
}

这个例子会打印出 less than five: 4。当 num 与模式中第一个分支匹配时,Some(4) 可以与 Some(x) 匹配,接着匹配守卫检查 x 值是否小于 5,因为 4 小于 5,所以第一个分支被选择。模式中无法提供类如 if x < 5 的表达能力,我们可以通过匹配守卫的方式来实现

match 表达式的模式中新建了一个变量而不是使用 match 之外的同名变量。内部变量覆盖了外部变量,意味着此时不能够使用外部变量的值,下面代码展示了如何使用匹配守卫修复这个问题。

fn main() {let x = Some(5);let y = 10;match x {Some(50) => println!("Got 50"),Some(n) if n == y => println!("Matched, n = {}", n),_ => println!("Default case, x = {:?}", x),}println!("at the end: x = {:?}, y = {}", x, y);
}

匹配守卫 if n == y 并不是一个模式所以没有引入新变量。这个 y 正是 外部的 y 而不是新的覆盖变量 y,这样就可以通过比较 n 和 y 来表达寻找一个与外部 y 相同的值的概念了。
也可以在匹配守卫中使用 或 运算符 | 来指定多个模式,同时匹配守卫的条件会作用于所有的模式。下面代码展示了匹配守卫与 | 的优先级。这个例子中看起来好像 if y 只作用于 6,但实际上匹配守卫 if y 作用于 4、5 和 6 ,在满足 x 属于 4 | 5 | 6 后才会判断 y 是否为 true:

let x = 4;
let y = false;match x {4 | 5 | 6 if y => println!("yes"),_ => println!("no"),
}

这个匹配条件表明此分支只匹配 x 值为 4、5 或 6 同时 y 为 true 的情况。

@绑定

@允许为一个字段绑定另外一个变量。下面例子中,我们希望测试 Message::Hello 的 id 字段是否位于 3…=7 范围内,同时也希望能将其值绑定到 id_variable 变量中以便此分支中相关的代码可以使用它。

enum Message {Hello { id: i32 },
}let msg = Message::Hello { id: 5 };match msg {Message::Hello { id: id_variable @ 3..=7 } => {println!("Found an id in range: {}", id_variable)},Message::Hello { id: 10..=12 } => {println!("Found an id in another range")},Message::Hello { id } => {println!("Found some other id: {}", id)},
}

上例会打印出 Found an id in range: 5。通过在 3…=7 之前指定 id_variable @,我们捕获了任何匹配此范围的值并同时将该值绑定到变量 id_variable 上。

使用 @ 还可以在绑定新变量的同时,对目标进行解构:

#[derive(Debug)]
struct Point {x: i32,y: i32,
}fn main() {// 绑定新变量 `p`,同时对 `Point` 进行解构let p @ Point {x: px, y: py } = Point {x: 10, y: 23};println!("x: {}, y: {}", px, py);println!("{:?}", p);let point = Point {x: 10, y: 5};if let p @ Point {x: 10, y} = point {println!("x is 10 and y is {} in {:?}", y, p);} else {println!("x was not 10 :(");}
}

@的新特性(rust1.53新增)

fn main() {match 1 {num @ (1 | 2) => {println!("{}", num);}_ => {}}
}

参考资料

  1. Rust语言圣经
  2. Rust程序设计语言

相关文章:

Rust模式匹配

模式匹配 模式匹配是从函数式编程语言&#xff08;例如&#xff1a;Haskell&#xff0c;Lisp&#xff09;吸收而来的&#xff0c;用于为复杂的类型系统提供一个轻松的解构能力。rust使用match来提供模式匹配的功能。mathc类似于其它编程语言中的switch-case&#xff0c;但是远…...

GIT:【基础一】必要配置和命令

目录 一、Git安装 二、基础命令 1.git config -l&#xff1a;git配置详细信息 2.git config --system -l&#xff1a;本地git系统自动配置的信息 3.git config --global -l&#xff1a;本地git用户自动配置的信息 4.where git&#xff1a; windows查看git安装目录 5.git各配置…...

黑马程序员-Linux系统编程-01

课程链接 01-Linux命令基础习惯-Linux系统编程_哔哩哔哩_bilibili 课程重点笔记 01-linux命令基础习惯 终端 终端&#xff1a;一切输入、输出的总称&#xff0c;因此终端并不是一定指的是命令行&#xff0c;只要是能进行输入或者输出即可&#xff0c;但是在linux终端上‘’内…...

Python|每日一练|动态规划|图算法|散列表|数组|双指针|单选记录:不同路径|求两个给定正整数的最大公约数和最小公倍数|删除有序数组中的重复项

1、不同路径&#xff08;数学&#xff0c;动态规划&#xff09; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”…...

Java常用框架(一)

思维导图 常见知识点 一、SpringBoot 1.简单介绍一下Spring及其优缺点 1.1 概念 重量级企业开发框架EJB的替代品&#xff0c;通过依赖注入、面向切面编程&#xff0c;使用简单Java对象POJO为企业Java开发提供了相对简单的方法。 1.2 优缺点 1.2.1 优点 组件代码轻量级 …...

基于 DSP+FPGA 的高清图像跟踪系统研制

目标识别与跟踪技术是目前图像处理研究的重点方向&#xff0c;在军事和民用领域中 具有广泛的应用价值&#xff0c;如精确制导武器、导弹飞机预警等军事领域&#xff0c;如交通管理、 刑事侦查等民用领域。其中&#xff0c;如何在复杂的背景中&#xff0c;提取、识别与跟踪特定…...

apisix部署

使用k8s部署前打包镜像&#xff1a; FROM centos:7 ARG APISIX_VERSION2.11.0 LABEL apisix_version“${APISIX_VERSION}” RUN yum install -y https://repos.apiseven.com/packages/centos/apache-apisix-repo-1.0-1.noarch.rpm && yum install -y https://repos…...

无聊小知识01.serialVersionUID的作用

什么是serialVersionUIDJava&#xff08;TM&#xff09;对象序列化规范中描述到&#xff1a;serialVersionUID用作Serializable类中的版本控件。如果您没有显式声明serialVersionUID&#xff0c;JVM将根据您的Serializable类的各个方面自动为您执行此操作。(http://docs.oracle…...

pytorch搭建手写数字识别LeNet-5网络,并用tensorRT部署

pytorch搭建手写数字识别LeNet-5网络&#xff0c;并用tensorRT部署前言1、pytorch 搭建LeNet-5&#xff0c;并转为ONNX格式1.1 LeNet-5网络介绍1.2 ONNX(Open Neural Network Exchange)介绍1.3 pytorch 搭建 LeNet5网络2、将onnx转为tensorRT2.1 tensorRT 介绍2.1 onnx 转为 te…...

扬帆优配|五千亿巨头一度涨停! 4天3倍,港股又现“狂飙”股!

周一&#xff0c;A股三大指数走势分化。到午间收盘&#xff0c;沪指震荡走高涨近1%&#xff0c;深证成指涨0.75%&#xff0c;创业板指继续弱势调整。 盘面上&#xff0c;钢铁、煤炭、大金融等权重板块团体走强&#xff0c;三大通讯运营商一同拉升&#xff0c;其间我国电信盘中一…...

RocketMQ之(一)RocketMQ入门

一、RocketMQ入门一、RocketMQ 介绍1.1 RocketMQ 是什么&#xff1f;1.2 RocketMQ 应用场景01、应用解耦02、流量削峰03、数据分发1.3 RocketMQ 核心组成01、NameServer02、Broker03、Producer04、Consumer1.6 运转流程1.5 RocketMQ 架构01、NameServer 集群02、Broker 集群03、…...

推荐系统[三]:粗排算法常用模型汇总(集合选择和精准预估),技术发展历史(向量內积,WideDeep等模型)以及前沿技术

1.前言:召回排序流程策略算法简介 推荐可分为以下四个流程,分别是召回、粗排、精排以及重排: 召回是源头,在某种意义上决定着整个推荐的天花板;粗排是初筛,一般不会上复杂模型;精排是整个推荐环节的重中之重,在特征和模型上都会做的比较复杂;重排,一般是做打散或满足…...

vue3 + vite 使用 svg 可改变颜色

文章目录vue3 vite 使用 svg安装插件2、配置插件 vite.config.js3、根据vite配置的svg图标文件夹&#xff0c;建好文件夹&#xff0c;把svg图标放入4、在 src/main.js内引入注册脚本5、创建一个公共SvgIcon.vue组件6.1 全局注册SvgIcon.vue组件6.2、在想要引入svg的vue组件中引…...

SQL82 返回 2020 年 1 月的所有订单的订单号和订单日期

描述Orders订单表order_numorder_datea00012020-01-01 00:00:00a00022020-01-02 00:00:00a00032020-01-01 12:00:00a00042020-02-01 00:00:00a00052020-03-01 00:00:00【问题】编写 SQL 语句&#xff0c;返回 2020 年 1 月的所有订单的订单号&#xff08;order_num&#xff09;…...

vulnhub zico2

总结&#xff1a;脏牛提权 目录 下载地址 漏洞分析 信息收集 木马上传 反弹shell 提权 下载地址 zico2.ova (Size: 828 MB)Download: https://www.dropbox.com/s/dhidaehguuhyv9a/zico2.ovaDownload (Mirror): https://download.vulnhub.com/zico/zico2.ova使用方法&…...

处理窗口的常用API函数及窗口处理经验总结(附源码)

目录 1、检测窗口状态 2、将窗口前置显示 2.1、将窗口拉到最前面显示 2.2、将窗口置顶显示 2.3、将窗口设置到指定窗口的上面 3、将不显示的窗口强行显示出来 4、获取窗口的信息 5、通过窗口信息去查找窗口 5.1、调用GetClassName接口去比对窗口的类名 5.2、调用Find…...

@TableId注解详细介绍

TableId注解是专门用在主键上的注解&#xff0c;如果数据库中的主键字段名和实体中的属性名&#xff0c;不一样且不是驼峰之类的对应关系&#xff0c;可以在实体中表示主键的属性上加Tableid注解&#xff0c;并指定Tableid注解的value属性值为表中主键的字段名既可以对应上。 …...

kubectl常用的命令

目录 安装 kubectl 一、命令自动补全 二、常用命令 1、查看所有pod列表 2、查看RC和service列表 3、显示Node的详细信息 4、显示Pod的详细信息, 特别是查看Pod无法创建的时候的日志 5、 根据yaml创建资源, apply可以重复执行&#xff0c;create不行 6、基于nginx.yaml…...

Linux 配置远程SSH服务(密码+密钥)

环境准备&#xff1a; 将虚拟机1恢复快照&#xff0c;然后手动配置一个NAT模式IP为192.168.200.100&#xff0c;hostname设置为fuwu1 将虚拟机1复制为虚拟机2&#xff0c;然后手动配置一个NAT模式IP为192.168.200.200&#xff0c;hostname设置为fuwu2 windows准备 xshell 或 pu…...

WuThreat身份安全云-TVD每日漏洞情报-2023-02-20

漏洞名称:Microsoft Exchange Server 远程执行代码漏洞 漏洞级别:高危 漏洞编号:CVE-2023-21529,CNNVD-202302-1075 相关涉及:Microsoft Exchange Server 2016 Cumulative Update 23 漏洞状态:POC 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-03822 漏洞…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...