表达式类型总结:
Expression type | Example | Related traits |
---|---|---|
Array literal | [1, 2, 3] | |
Repeat array literal | [0; 50] | |
Tuple | (6, “crullers”) | |
Grouping | (2 + 2) | |
Block | { f(); g() } | |
Control flow expressions | if ok { f() } | |
if ok { 1 } else { 0 } | ||
if let Some(x) = f() { x } else { 0 } | ||
match x { None => 0, _ => 1 } | ||
for v in e { f(v); } | std::iter::IntoIterator | |
while ok { ok = f(); } | ||
while let Some(x) = it.next() { f(x); } | ||
loop { next_event(); } | ||
break | ||
continue | ||
return 0 | ||
Macro invocation | println!(“ok”) | |
Path | std::f64::consts::PI | |
Struct literal | Point {x: 0, y: 0} | |
Tuple field access | pair.0 | Deref , DerefMut |
Struct field access | point.x | Deref , DerefMut |
Method call | point.translate(50, 50) | Deref , DerefMut |
Function call | stdin() | Fn(Arg0, …) -> T , FnMut(Arg0, …) -> T , FnOnce(Arg0, …) -> T |
Index | arr[0] | Index , IndexMut |
Deref
, DerefMut |
| Error check | create_dir(“tmp”)? | |
| Logical/bitwise NOT | !ok | Not |
| Negation | -num | Neg |
| Dereference | ptr | Deref
, DerefMut |
| Borrow | &val | |
| Type cast | x as u32 | |
| Multiplication | n 2 | Mul |
| Division | n / 2 | Div |
| Remainder (modulus) | n % 2 | Rem |
| Addition | n + 1 | Add |
| Subtraction | n - 1 | Sub |
| Left shift | n << 1 | Shl |
| Right shift | n >> 1 | Shr |
| Bitwise AND | n & 1 | BitAnd |
| Bitwise exclusive OR | n ^ 1 | BitXor |
| Bitwise OR | n | 1 | BitOr |
| Less than | n < 1 | std::cmp::PartialOrd |
| Less than or equal | n <= 1 | std::cmp::PartialOrd |
| Greater than | n > 1 | std::cmp::PartialOrd |
| Greater than or equal | n >= 1 | std::cmp::PartialOrd |
| Equal | n == 1 | std::cmp::PartialEq |
| Not equal | n != 1 | std::cmp::PartialEq |
| Logical AND | x.ok && y.ok | |
| Logical OR | x.ok || backup.ok | |
| End-exclusive range | start .. stop | |
| End-inclusive range | start ..= stop | |
| Assignment | x = val | |
| Compound assignment | x *= 1 | MulAssign |
| | x /= 1 | DivAssign |
| | x %= 1 | RemAssign |
| | x += 1 | AddAssign |
| | x -= 1 | SubAssign |
| | x <<= 1 | ShlAssign |
| | x >>= 1 | ShrAssign |
| | x &= 1 | BitAndAssign |
| | x ^= 1 | BitXorAssign |
| | x |= 1 | BitOrAssign |
| Closure | |x, y| x + y | |
声明
声明变量的时候可以不初始化,在后面的代码里的第一次赋值相当于初始化,但如果声明的时候没加mut
则变量只能被赋值一次,相当于final
。而且在赋值之前变量是不能使用的。
match
match语句会被编译器优化成jump table,比如:假如所有的情况的条件都是常数,则编译器会把各种条件变成一个数组。
循环
虽然循环是表达式,但while
和for
的返回值是()
,所以没啥用。break可以用来返回loop的值。
在for i in 0..20
中0..20
和std::ops::Range{start: 0, end: 20}
是相同的。因为Range
实现了std::iter::IntoIterator
trait。0..=20
是包含20
的。用于for的变量是转移的,如果不想转移用&v
或二者&mut v
。
生命周期可以做循环的标签,break指定的标签可以跳出相应的循环。
'search:
for room in apartment {
for spot in room.hiding_spots() {
if spot.contains(keys) {
println!("Your keys are {} in the {}.", spot, room);
break 'search;
}
}
}
break还可以既指定标签又指定返回值:break 'outer value
。continue
也可以指定标签。
return
函数的返回值推荐用表达式,而return
一般用在提前返回。
loop的存在意义和无返回类型
因为流程敏感性(flow-sensitive)的检查:
- 不同的路径的返回值都是相同的类型,想要这样编译器必须知道代码是不是能走到最后
- 编译器会检查不同路径是不是会遇到未初始化的变量
- 编译器会警告永远也到不了的代码
flow-sensitive检查要在简洁和聪明之间做抉择,rust选择了简单,因此rust会拒绝一些实际上可用的代码:
fn wait_for_process(process: &mut Process) -> i32 {
while true {
if process.wait() {
return process.exit_code();
}
}
} // error: mismatched types: expected i32, found ()
之所以出现上面的错误是,rust不会去检查循环或判断的分支的条件,而是简单的任务任何情况都可能,所以虽然实际上上面的代码可以返回正确的类型,但rust不会去检查,而是认为while
的返回值就是()
。
还有在if
判断或者其它流程中,rust是要求必须有相同的返回类型的,但如果程序出现了break
,panic
或者std::process::exit()
这种非正常返回的情况时,要求他们的类型和所处表达式的类型一致是无意义的。所以rust给这些非正常返回值一个特殊的类型!
,这个类型不会被类型检查。返回类型是!
的函数被称为发散函数。
函数和方法
泛型的函数和方法调用不能用:Vec<i32>::with_capacity(1000)
,(0 .. n).collect<Vec<i32>>()
因为在表达式里<>会被当作小于号和大于号。
正确的方法应该用turbofish操作符:Vec::<i32>::with_capacity(1000)
,(0 .. n).collect::<Vec<i32>>()
也可以通过类型推断let ramp: Vec
range
range可以省略开始或接尾,但不能都省略,省略了结尾的range也是可以做迭代器的:for i in 1.. {}
。只不过这样会无限循环下去。
运算
溢出和不合法的操作在debug模式和release模式可能有不同的行为,但标准库有各种方法处理这些行为。
求余结果的符号和被除数相同。浮点数也可以求余:let x = 1234.567 % 10.0; // approximately 4.567
位运算符号中!被用左取反操作,所以不要用!n在判断n是否为零。
类型转换
浮点数转整型往靠近0的方向转:-1.99 as i32 == -1
。浮点数转整数如果超过整数的表示范围则取该类型和原值最接近的数:1e6 as u8 == 255
。
bool
和char
可以转成任何的整型,但反过来不行,u8转char例外,因为所有的u8都是合法的char。如果想要把整型转char可以用std::char::from_u32()
,这个方法会检查数值是否合法,返回Option<char>
。
一些引用类型和指针类型可以省略转换。