滕州市燕猫虎计算机科技工作室个体工商户头像
关注
《Rust程序设计》学习笔记五封面图

《Rust程序设计》学习笔记五

===^^===
《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用:
https://blog.csdn.net/look4liming/article/details/164755808文章配图https://blog.csdn.net/look4liming/article/details/164755808

Rust是表达式语言。

if和switch是语句,他们不生成值,也不能在表达式中间使用,而在Rust中,if和match可以生成值。

所有可以链式书写的运算符都是左结合的。

比较运算符、赋值运算符和范围运算符,则根本无法链式书写。

如果一个块看起来很像C代码,每个地方都有分号,那么它就会像C的块一样运行,并且其值为()。

当块的最后一行不带分号时,就以最后这个表达式的值而不是通常的()作为块的值。

在Rust中,分号是有实际意义的:

let msg = {

// let声明:分号总是必须的

let dandelion_control = puffball.open();

// 带分号的表达式:调用方法,丢弃返回值

dandelion_control.release_all_seeds(launch_codes);

// 无分号的表达式:调用方法,返回值将存入msg

dandelion_control.get_status();

};

变量名必须以字母或下划线开头,并且只能在第一个字母之后包含数字。“字母”是广义的,包括希腊字母、带重音的拉丁字符和更多符号,也包括中文。不允许使用表情符号。

let声明可以在不初始化变量的情况下声明变量,因为有时候确实应该在某些控制流结构的中间初始化变量:

let name;

if user.has_nickname() {

name = user.nickname();

} else {

name = generate_unique_name();

user.register(&name);

}

在初始化之前就使用变量是错误的。

看这段代码:

for line in file.lines() {

let line = line?;

}

for循环里的这个let声明,会创建一个不同类型的、新的变量。第二个定义会在所处代码块的其余部分代替第一个定义,这叫作遮蔽(shadowing)。

块还可以包含语法项声明,比如fn、struct或use。

当在块内声明一个fn时,它的作用域是整个块,也就是说,它可以在这个封闭块内部使用。但是嵌套的fn无法访问恰好在同一作用域内的局部变量或参数。闭包可以看到封闭块作用域内的变量。

if表达式示例:

if condition1 {

block1

} else if condition2 {

block2

} else {

block_n

}

每个condition都必须是bool类型的表达式。condition周围不需要圆括号,但花括号是必须的。

else if块以及最后的else是可选的。

match表达式示例:

match code {

0 => println!("OK"),

1 => println!("Wires Tangled"),

2 => println!("User Asleep"),

_ => println!("Unrecognized Error {}", code)

}

match表达式的一般形式如下:

match value {

pattern => expr,

...

}

如果expr是一个块,可以省略此分支之后的逗号。

Rust禁止执行未覆盖所有可能值的match表达式:

let score = match card.rank {

Jack => 10,

Queen => 10,

Ace => 11

}; // 错误,为穷举所有模式

if表达式的所有块都必须生成相同类型的值。

match表达式的所有分支都必须具有相同的类型。

if let表达式:

if let pattern = expr {

block1

} else {

block2

}

expr要么匹配pattern,运行block1;要么运行block2。

if let是只有一个模式的match的简写形式:

match expr {

pattern => { block1 }

_ => { block2 }

}

4种循环表达式:

while condition {

block

}

while let pattern = expr {

block

}

loop {

block

}

for pattern in iterable {

block

}

各种循环都是Rust中的表达式,但while循环或for循环的值总是()。

可以用loop来编写无限循环。

看下面这个for循环:

for i in 0..20 {

println!("{}", i);

}

..运算符会生成一个范围(range),及具有两个字段(start和end)的简单结构体。0..20与std::ops::Range {start: 0, end: 20}相同。

标准集合都是可迭代的,数组和切片也是如此。

为了与Rust的移动语义保持一致,把值用于for循环会消耗该值:

let strings: Vec<String> = error_messages();

for s in strings { // 在这里,每个String都会转移给s

println!("{}", s);

} // 并在此丢弃

println!("{} error(s)", srings.len()); // 错误,使用了已经转移出去的值

这可能很不方便,补救措施是在循环中访问此集合的引用。循环变量也会变成对集合中每个条目的引用:

for rs in &strings {

println!("String {:?} is at address {:p}.", *rs, rs);

}

这里&string的类型是&Vec<String>,rs的类型是&String。

遍历可变引用会为每个元素提供一个可变引用:

for rs in &mut strings { // rs的类型是&mut String

rs.push('\n'); // 为每个字符串添加一个换行

}

break表达式会推出所在循环。break只能用在循环中,不能用在match表达式中,这与C系语言中的switch语句不同。

在loop循环体中,可以在break后面跟一个表达式,该表达式的值会成为此loop的值:

continue表达式会跳转到循环的下一次迭代。

循环可以带有生命周期标签:

'search: // 生命周期标签

for room in apartment {

for spot in room.hiding_spots() {

if spot.contains(keys) {

break 'search;

}

}

}

break可以同时具有标签和值表达式:

// 找到此系列中的第一个完全平方数的平方根

let spart = 'outer: loop {

let n = next_number();

for i in 1.. {

let square = i * i;

if square == n {

break 'outer i; // 找到了平方根,跳出最外层循环,把i给spart

}

if square > n {

break;

}

}

};

return表达式会退出当前函数,并向调用者返回值。

不带值的return是return ()的简写:

fn f() {

return; // 返回()

}

函数调用与方法调用:

let x = gcd(1302, 462); // 函数调用

let room = player.location(); // 方法调用

在上面的代码中,player可能是Player、&Player类型的引用,也可能是Box<Player>或Rc<Player>类型的智能指针,因为Rust的.运算符会根据需要自动对player解引用或接入对它的引用。

普通方法会在值上调用,如my_vec.len()

类型关联函数会在类型是调用,如Vec::new()

在函数调用或方法调用中,泛型类型的常用语法Vec<T>是不起作用的:

return Vec<i32>::with_capacity(1000); // 错误

let ramp = (0..n).collect<Vec<i32>>(); // 同样错误

在表达式中<是小于运算符,Rust编译期建议用::<T>代替<T>:

return Vec::<i32>::with_capacity(1000);

let ramp = (0..n).collect::<Vec<i32>>();

或者删掉类型参数,让Rust来推断它们:

return Vec::with_capacity(1000);

let ramp: Vec<i32> = (0..n).collect();

字段与元素:

game.black_pawns // 结构体字段

coords.1           // 元组元素

如果.左边的值是引用或智能指针类型,那么它就会像方法调用一样自动解引用。

方括号会访问数组、切片或向量的元素:

pieces[i] // 数组元素

方括号左侧的值也会自动解引用。

..运算符允许省略任何操作数:

.. // RangeFull

a.. // RangeFrom {start: a}

..b // RangeTo {end: b}

a..b // Range {start: a, end: b}

后两种是排除结束值(或半开放)的。例如,范围0..3包括数值0、1和2,但不包括3。

..=运算符会生成包含结束值(或封闭)的范围:

..=b // RangeToInclusive {end: b}

a..=b // RangeInclusive::new(a, b)

例如,范围0..=3包括数值0、1、2和3。

一元*运算符用于访问引用所指向的值。看下面的程序:

let padovan: Vec<u64> = compute_padovan_sequence(n);

for elem in &padovan {

draw_triangle(turtle, *elem);

}

elem的类型是&u64,因此*elem为u64。

一元-运算符会对一个数取负,它支持除无符号整数之外的所有数值类型。

没有一元+运算符!

%取余运算符,既能用于整数,也能用于浮点数。

Rust支持C系语言中的整数位运算符(&、|、^、<<和>>)。但是,Rust会使用!而不是~表示按位非。

移位总是对有符号整数类型进行符号扩展,对无符号数进行零扩展。由于Rust支持无符号数,所以它不需要>>>这样的无符号移位运算符。

Rust不支持链式赋值,不能编写a=b=3来将3同时赋给a和b。

Rust没有自增运算符++和自减运算符--。

将一种类型转换成另一种类型,需要显式转换:

let x = 17; // x是i32的

let index = x as usize; // 通过as关键字,将i32转换成usize

闭包通常由一个参数列表组成,在两条竖线之间列出,后跟一个表达式:

let is_even = |x| x % 2 == 0;

如果确实指定了返回类型,那么为了语法的完整性,闭包的主体必须是一个块:

let is_even = |x: u64| -> bool x % 2 == 0; // 错误

let is_even = |x: u64| -> bool { x % 2 == 0; } // 正确

调用闭包和调用函数的语法是一样的:

is_even(14);

===^^===
《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用:
https://blog.csdn.net/look4liming/article/details/164755808文章配图https://blog.csdn.net/look4liming/article/details/164755808

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/look4liming/article/details/167282638

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--