长沙建站工作室,专注网站开发,仁怀网站建设,wordpress修改样式一、模式是什么
模式是Rust中特殊的语法#xff0c;它用来匹配值
二、模式的使用场景
#xff08;一#xff09;match match的每个分支箭头左边部分就是模式。
match VALUE {PATTERN EXPRESSION,PATTERN EXPRESSION,PATTERN EXPRESSION,
}例子
match x …一、模式是什么
模式是Rust中特殊的语法它用来匹配值
二、模式的使用场景
一match match的每个分支箭头左边部分就是模式。
match VALUE {PATTERN EXPRESSION,PATTERN EXPRESSION,PATTERN EXPRESSION,
}例子
match x {None None,Some(i) Some(i 1),
}箭头左边的None和Some(i)就是模式。
二if let
例子
fn main() {let favorite_color: Optionstr None;let is_tuesday false;let age: Resultu8, _ 34.parse();if let Some(color) favorite_color {println!(Using your favorite color, {color}, as the background);} else if is_tuesday {println!(Tuesday is green day!);} else if let Ok(age) age {if age 30 {println!(Using purple as the background color);} else {println!(Using orange as the background color);}} else {println!(Using blue as the background color);}
}if let后面的Some(color) 和 Ok(age)就是模式。 如果用户指定了中意的颜色就使用它。如果没有指定且今天是星期二就使用绿色。如果用户指定了他们的年龄并能够成功解析为数字的话我们将根据这个数字使用紫色或者橙色。最后如果没有一个条件符合就使用蓝色。
三while let
例子
let mut stack Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) stack.pop() {println!({}, top);
}while let后面的Some(top) 就是模式。 pop方法取出vector的最后一个元素并返回Some(value)。如果vector是空的它返回None。while循环只要pop返回Some就会一直运行其块中的代码。一旦其返回Nonewhile循环停止。我们可以使用while let来弹出栈中的每一个元素。
四for
例子
let v vec![a, b, c];
for (index, value) in v.iter().enumerate() {println!({} is at index {}, value, index);
}
运行结果
a is at index 0
b is at index 1
c is at index 2(index, value)就是模式 enumerate方法返回一个元组元组元素分别是索引和值。第一个是元组 (0, ‘a’)。当这个值匹配模式 (index, value)时index将会是0而value将会是 ‘a’
五let
let PATTERN value;例子
let x 5;x就是一个模式。
let (x, y, z) (1, 2, 3);(x, y, z) 也是一个模式。Rust会比较值 (1, 2, 3) 与模式 (x, y, z) 并发现此值匹配这个模式。在这个例子中将会把1绑定到x2绑定到y并将3绑定到z。 如果模式中元素的数量不匹配值中元素的数量则整个类型不匹配并会得到一个编译错误。
let (x, y) (1, 2, 3);一个错误的模式结构
六函数参数 函数参数也可以是模式。 例子
fn foo(x: i32) {// code goes here
}x就是一个模式类似于let中的模式。
fn print_coordinates((x, y): (i32, i32)) {println!(Current location: ({}, {}), x, y);
}
fn main() {let point (3, 5);print_coordinates(point);
}这会打印出Current location: (3, 5)。值 (3, 5) 会匹配模式 (x, y)如此x得到了值3而y得到了值5。
七闭包参数 闭包参数也可以是模式。与函数参数一样。
三、refutable与irrefutable模式的区别
模式有两种refutable可反驳的和irrefutable不可反驳的。 能匹配任何值的模式称为不可反驳的irrefutable。一个例子是let x 5; 语句中的x因为x可以匹配任何值所以不可能会失败。 不能匹配任何值的的模式称为可反驳的refutable。一个例子是if let Some(x) a_value表达式中的Some(x)如果变量a_value中的值是None那么Some(x) 模式不能匹配。
函数参数、let、for只能使用不可反驳的模式 if let和while let只能使用可反驳的模式因为根据定义他们意在处理可能的失败条件表达式的功能就是根据成功或失败执行不同的操作。
let Some(x) some_option_value;尝试在let中使用可反驳模式编译错误 Some(x)是可反驳的。如果some_option_value的值是None其不会匹配模式Some(x)。 可以使用if let。如此如果模式不匹配大括号中的代码将被忽略其余代码保持有效。
if let Some(x) some_option_value {println!({}, x);
}尝试把不可反驳模式用到if let上编译器会给出一个警告
if let x 5 {println!({}, x);
};match必须使用可反驳模式除了最后一个分支需要使用能匹配任何剩余值的不可反驳模式。
四、模式语法
一字面量模式
句法
LiteralPattern :BOOLEAN_LITERAL| CHAR_LITERAL| BYTE_LITERAL| STRING_LITERAL| RAW_STRING_LITERAL| BYTE_STRING_LITERAL| RAW_BYTE_STRING_LITERAL| -? INTEGER_LITERAL字面量模式能匹配字面量。 字面量模式总是可反驳型的。
示例
for i in -2..5 {match i {-1 println!(Its minus one),1 println!(Its a one),2|4 println!(Its either a two or a four),_ println!(Matched none of the arms),}
}-1、1、2、4都是字面量模式
二标识符模式
句法
IdentifierPattern :ref? mut? IDENTIFIER ( Pattern ) ?标识符模式只能包含一个标识符能匹配任何值并将值绑定到该标识符上。 标识符模式总是不可反驳型的。 最常见的标识符模式应用场景就是用在let上和函数包括闭包的参数上。
let mut variable 10;
fn sum(x: i32, y: i32) - i32 {默认情况下标识符模式里变量会和匹配到的值的一个副本绑定或值自身移动过来和变量绑定具体是使用拷贝语义还是移动语义取决于匹配到的值是否实现了 Copy。也可以使用关键字ref将变量和值的引用绑定或者使用ref mut将变量和值的可变引用绑定。示例
match a {None (),Some(value) (),
}
match a {None (),Some(ref value) (),
}在第一个匹配表达式中值被拷贝或移动到变量value上。在第二个匹配中值的引用被绑定到变量上。之所以需要这种句法是因为在解构时操作符 不能应用在值的字段上。例如以下内容无效
if let Person { name: person_name, age: 18..150 } value { }要使其有效请按如下方式编写代码
if let Person { name: ref person_name, age: 18..150 } value { }这里ref不是被匹配的一部分。它唯一的目的就是使变量和匹配值的引用绑定起来而不是潜在地拷贝或移动匹配到的内容。 模式 允许我们在创建一个变量的同时测试其值是否匹配模式。使用 可以在一个模式中同时测试和保存变量值。 示例
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。 第一个分支只有id的值在3到7之间才匹配此模式才将id的值赋给id_variable。 第二个分支只在模式中指定了一个范围id字段的值可以是10、11或12不过这个分支不能使用id的值因为没有将id值保存进一个变量。 最后一个分支使用了结构体字段简写语法此分支没有测试任何值都会匹配此分支。因此可以使用id的值。
三通配符模式
句法
WildcardPattern :_通配符模式下划线符号能与任何值匹配。常用它来忽略那些无关紧要的值。在其他模式中使用该模式时它匹配单个数据字段与和匹配所有其余字段的..相对。与标识符模式不同它不会复制、移动或借用它匹配的值。 通配符模式总是不可反驳型的。
示例
let (a, _) (10, x); // x一定会被 _ 匹配上
let real_part |a: f64, _: f64| { a };// 忽略一个函数/闭包参数
let RGBA{r: red, g: green, b: blue, a: _} color;// 忽略结构体的一个字段
if let Some(_) x {}// 能接收带任何值的任何Some四剩余模式
句法
RestPattern :..剩余模式匹配之前之后没有匹配的零个或多个元素。它只能在元组模式、元组结构体模式、切片模式中使用并且只能作为这些模式中的一个元素出现一次。当作为标识符模式的子模式时它也可出现在切片模式里。 剩余模式总是不可反驳型的。
示例
match value {[] println!(slice is empty),[one] println!(single element {}, one),[head, tail ..] println!(head{} tail{:?}, head, tail),//作为标识符模式的子模式
}
match slice {// 忽略除最后一个元素以外的所有元素并且最后一个元素必须是 !.[.., !] println!(!!!),// start 是除最后一个元素之外的所有元素的一个切片最后一个元素必须是 “z”。[start .., z] println!(starts with: {:?}, start),// end 是除第一个元素之外的所有元素的一个切片第一个元素必须是 “a”[a, end ..] println!(ends with: {:?}, end),rest println!({:?}, rest),
}
if let [.., penultimate, _] slice {println!(next to last is {}, penultimate);
}
// 剩余模式也可是在元组和元组结构体模式中使用。
match tuple {(1, .., y, z) println!(y{} z{}, y, z),(.., 5) println!(tail must be 5),(..) println!(matches everything else),
}五区间模式
句法
RangePattern :RangePatternBound .. RangePatternBound
RangePatternBound :CHAR_LITERAL| BYTE_LITERAL| -? INTEGER_LITERAL| PathInExpression| QualifiedPathInExpression区间模式匹配封闭区间内的值。例如一个模式m..p将只能匹配值’m’、‘n’、‘o’ 和 ‘p’。它的边界值可以是字面量也可以是指向常量值的路径。 一个模式a .. b必须总是a≤b。例如10..0这样的区间模式是错误的。 区间模式只适用于标量类型。可接受的类型有
整型u8、i8、u16、i16、usize、isize ...。
字符型char。示例
let valid_variable match c {a..z true,A..Z true,α..ω true,_ false,
};
println!({}, match ph {0..6 acid,7 neutral,8..14 base,_ unreachable!(),
});
// 使用指向常量值的路径
println!({}, match altitude {TROPOSPHERE_MIN..TROPOSPHERE_MAX troposphere,STRATOSPHERE_MIN..STRATOSPHERE_MAX stratosphere,MESOSPHERE_MIN..MESOSPHERE_MAX mesosphere,_ outer space, maybe,
});
if let size binary::MEGA..binary::GIGA n_items * bytes_per_item {println!(这适用并占用{}个字节, size);
}
// 使用路径
println!({}, match 0xfacade {0 .. u8 as MaxValue::MAX fits in a u8,0 .. u16 as MaxValue::MAX fits in a u16,0 .. u32 as MaxValue::MAX fits in a u32,_ too big,
});当区间模式匹配某非usize和 非isize整型类型和字符型(char)的整个值域时此模式是不可反驳型的。例如0u8..255u8是不可反驳型的。某类整型的值区间是从该类型的最小值到该类型最大值的闭区间。字符型(char)的值的区间就是那些包含所有Unicode标量值的区间即 \u{0000}..\u{D7FF} 和 \u{E000}..\u{10FFFF}。
六引用模式
句法
ReferencePattern :(|) mut? PatternWithoutRange引用模式对匹配到的指针做解引用 例如下面两个匹配是等效的
let int_reference 3;
let a match *int_reference { 0 zero, _ some };
let b match int_reference { 0 zero, _ some };
assert_eq!(a, b);引用模式要求必须使用 来匹配对引用的引用因为 本身是一个单独的token而不是两个 token。 举例
let a Some(10);
match a {Some( value ) println!({}, value),None {}
}引用模式中添加关键字mut可对可变引用做解引用。引用模式中的可变性标记必须与值的引用的可变性匹配。 引用模式总是不可反驳型的。
七结构体模式
句法
StructPattern :PathInExpression {StructPatternElements ?}
StructPatternElements :StructPatternFields (, | , StructPatternEtCetera)?| StructPatternEtCetera
StructPatternFields :StructPatternField (, StructPatternField) *
StructPatternField :OuterAttribute *(TUPLE_INDEX : Pattern| IDENTIFIER : Pattern| ref? mut? IDENTIFIER)
StructPatternEtCetera :OuterAttribute *..结构体模式匹配结构体值。它也被用来解构结构体。 在结构体模式中结构体字段需通过名称、索引对于元组结构体来说来指代或者通过使用..来忽略
match s {Point {x: 10, y: 20} (),Point {y: 10, x: 20} (), // 顺序没关系Point {x: 10, ..} (),Point {..} (),
}
match t {PointTuple {0: 10, 1: 20} (),PointTuple {1: 10, 0: 20} (), // 顺序没关系PointTuple {0: 10, ..} (),PointTuple {..} (),
}
如果没使用 ..需要提供所有字段的详尽匹配
match struct_value {Struct{a: 10, b: X, c: false} (),Struct{a: 10, b: X, ref c} (),Struct{a: 10, b: X, ref mut c} (),Struct{a: 10, b: X, c: _} (),Struct{a: _, b: _, c: _} (),
}IDENTIFIER能匹配任意值并将其绑定到变量上。
let Struct{a: x, b: y, c: z} struct_value; // 解构所有的字段当一个结构体模式的子模式是可反驳型的那这个结构体模式就是可反驳型的。
解构结构体
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);
}
或者
struct Point {x: i32,y: i32,
}
fn main() {let p Point { x: 0, y: 7 };let Point { x, y } p;assert_eq!(0, x);assert_eq!(7, y);
}这段代码创建了变量x和y与变量p中的x和y相匹配。其结果是变量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}));}}
}第一个分支通过指定字段y匹配字面值0来匹配任何位于x轴上的点。此模式仍然创建了变量x以便在分支的代码中使用。 第二个分支通过指定字段x匹配字面值0来匹配任何位于y轴上的点并为字段y创建了变量y。 第三个分支没有指定任何字面值所以其会匹配任何其他的Point并为x和y两个字段创建变量。 在这个例子中值p因为其x包含0而匹配第二个分支因此会打印出On the y axis at 7。 记住match表达式一旦找到一个匹配的模式就会停止检查其它分支所以即使Point { x: 0, y: 0} 在x轴上也在y轴上这些代码也只会打印On the x axis at 0。
八元组结构体模式
句法
TupleStructPattern :PathInExpression ( TupleStructItems? )
TupleStructItems :Pattern ( , Pattern )* ,?元组结构体模式匹配元组结构体值和枚举值。它还被用于解构元组结构体值或枚举值。 当元组结构体模式的一个子模式是可反驳型的则该元组结构体模式就是可反驳型的。
九元组模式
句法
TuplePattern :( TuplePatternItems? )
TuplePatternItems :Pattern ,| RestPattern| Pattern (, Pattern) ,?元组模式匹配元组值。它们还被用来解构元组值。 内部只带一个剩余模式的元组模式(..) 可以匹配任意长度的元组。 当元组模式的一个子模式是可反驳型的那该元组模式就是可反驳型的。 使用元组模式的示例
let pair (10, ten);
let (a, b) pair;
assert_eq!(a, 10);
assert_eq!(b, ten);十切片模式
句法
SlicePattern :[ SlicePatternItems? ]
SlicePatternItems :Pattern (, Pattern)* ,?切片模式可以匹配固定长度的数组和动态长度的切片。
// 固定长度
let arr [1, 2, 3];
match arr {[1, _, _] 从1开始,[a, b, c] 从其他值开始,
};// 动态长度
let v vec![1, 2, 3];
match v[..] {[a, b] { /* 这个分支不适用因为长度不匹配 */ }[a, b, c] { /* 这个分支适用 */ }_ { /* 这个通配符是必需的因为长度不是编译时可知的 */ }
};在匹配数组时只要每个元素是不可反驳型的切片模式就是不可反驳型的。当匹配切片时只有单个..或带有 ..作为子模式的标识符模式的情况才是不可反驳型的。
十一路径模式
句法
PathPattern :PathInExpression| QualifiedPathInExpression路径模式是指向常量值或指向没有字段的结构体或没有字段的枚举变体的模式。
非限定路径模式可以指向
枚举变体
结构体
常量
关联常量限定路径模式只能指向关联常量。 常量不能是联合体类型。结构体常量和枚举常量必须带有 #[derive(PartialEq, Eq)] 属性不只是实现。 当路径模式指向结构体或枚举变体(枚举只有一个变体)或类型为不可反驳型的常量时该路径模式是不可反驳型的。当路径模式指向的是可反驳型常量或带有多个变体的枚举时该路径模式是可反驳型的。
解构枚举
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 {x} and in the y direction {y});}Message::Write(text) {println!(Text message: {text});}Message::ChangeColor(r, g, b) {println!(Change the color to red {r}, green {g}, and blue {b},)}}
}这段代码会打印出Change the color to red 0, green 160, and blue 255。尝试改变msg的值来观察其他分支代码的运行。 对于像Message::Quit这样没有任何数据的枚举成员不能进一步解构其值。只能匹配其字面值Message::Quit因此模式中没有任何变量。 对于像Message::Move这样的类结构体枚举成员可以采用类似于匹配结构体的模式。在成员名称后使用大括号并列出字段变量以便将其分解以供此分支的代码使用。这里使用了示例18-13所展示的简写。 对于像Message::Write这样的包含一个元素以及像Message::ChangeColor这样包含三个元素的类元组枚举成员其模式则类似于用于解构元组的模式。模式中变量的数量必须与成员中元素的数量一致。
解构嵌套的结构体和枚举 目前为止所有的例子都只匹配了深度为一级的结构体或枚举不过当然也可以匹配嵌套的项例如
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 color to red {r}, green {g}, and blue {b});}Message::ChangeColor(Color::Hsv(h, s, v)) {println!(Change color to hue {h}, saturation {s}, value {v})}_ (),}
}第一个分支的模式匹配一个包含Color::Rgb枚举成员的Message::ChangeColor枚举成员然后模式绑定了3个内部的i32值。 第二个分支的模式也匹配一个Message::ChangeColor枚举成员但是其内部的枚举会匹配Color::Hsv枚举成员。 我们可以在一个match表达式中指定这些复杂条件即使会涉及到两个枚举。
十二分组
句法
GroupedPattern :( Pattern )将模式括在圆括号内可用来显式控制模式的优先级。例如像 0..5这样的引用模式和区间模式相邻就会引起歧义这时可以用圆括号来消除歧义。
let int_reference 3;
match int_reference {(0..5) (),_ (),
}十三并列 pattern | pattern 匹配两个或多个并列子模式例如A | B | C中的一个的模式。除了let绑定和函数参数包括闭包参数可以在任何场景使用