Variables¶
声明¶
Rust中用于声明变量的关键字是let,它的语法如下:
let [mut] <variable>[: <type>] [= <value>];
其中,类型和初始化的值都可以省略。如果一个变量从声明开始没有被赋值,就不能使用这个变量。如果没有指定类型但指定了初始化值,系统则会自动推断变量的类型。Rust还可以用{}来用一系列语句来初始化变量,也可以用()来一次性声明多个变量。没有用mut声明的变量是不可变的,不能被修改。
Rust中用于声明常量的关键字是const,用于声明静态变量的关键字是static。语法与let相似,但需要同时指定类型和初始化值。通常const和static语句都是在全局作用域(即函数外)中声明的。
let可以用来重新声明一个变量,隐藏之前的变量,也可以用mut来改变一个变量的可变性。
1 2 3 4 5 6 7 8 9 | |
变量类型¶
Rust的变量类型有
- 一般类型
- 布尔:
bool,取值为true或false,占用1个字节。 - 字符:
char,使用单引号,占用4个字节。 - 整数:
i8~i128和isize,取值范围为\([-2^{n-1}, 2^{n-1} - 1]\),可以用min_value()和max_value()函数来获取类型的取值范围。isize的取值范围和系统指针长度相同。默认的整数类型是i32。 - 无符号整数:
u8~u128和usize,取值范围为\([0, 2^n - 1]\)。 - 浮点数:
f32和f64,分别为单精度和双精度浮点数。默认的浮点数类型是f64。 - 字符串字面量:
str,使用双引号,是不可变类型。字符串字面量(变量)的类型为&str,是引用类型。 - 字符串:
String,是可变类型,但不支持索引。字符串的引用或切片类型为&str。 - 单元类型:
(),只有一个值(),没有return语句的函数的返回值类型为(),不占用内存。
- 布尔:
- 容器及相关类型
- 使用
println!打印容器时,需要用{:?}或{:#?},前者为一行输出,后者在每个元素后面添加换行符。 - 定长数组:
[T; N],其中T为数组元素类型或重复的数组,N为数组长度,必须是常量。只有用mut声明的数组才能修改其中元素。- 注意不支持
Copytrait的类型不能用[T; N]语法,必须逐个赋值。 - 不同长度的数组是不同的类型,不能相互赋值。
- 注意不支持
- 定长元组:
(T1, T2, ..., Tn),其中T1~Tn为元组中元素的类型。只有用mut声明的元组才能修改其中元素(类型必须匹配)。类似于Python,在变量声明阶段或赋值阶段,仅包含(可以被赋值的)变量元组可以作为赋值运算的左端项,此时会分别为每个变量分配对应的值,省略的变量用_表示。元组支持嵌套。单元素元组的语法为(<value>,)。 - 数组切片:
&<parent>[<start>..<end>],注意切片是对<parent>的引用,是引用类型。元组不支持切片,只能用.0、.1等来访问元素,类型为[T]。
- 使用
- 迭代器,通常由容器对象的
iter()方法生成。 - 函数:需要用
fn(arg1: type1, ...) -> return_type表示,函数以引用的方式传递。
整数类型¶
Rust中的整数字面量有如下写法:
- 十进制:
123_456 - 十六进制:
0x123,0x开头,数字为0-9和a-f - 八进制:
0o123,0o开头,数字为0-7 - 二进制:
0b101,0b开头,数字为0和1 - 字节:
b'A' - 下划线
_类似于千位分隔符,存在与否不影响数字的值
整数溢出
在Debug模式下,Rust会检查整数溢出,如果发生溢出,程序会panic。在Release模式下,Rust不会检查整数溢出,溢出后会按照二进制补码进行循环。
整数类型有如下方法:
- 下文中的
*指add、sub、mul、div等运算 wrapping_*:如果运算溢出,则取溢出后的值。checked_*:如果运算溢出,则返回None。saturating_*:如果运算溢出,则返回目标类型的最大值或最小值。-
overflowing_*:返回运算结果和是否溢出的标记let a: i32 = 1; let b: i32 = 2; let (c, overflow) = a.overflowing_add(b); println!("{} {}", c, overflow); // 3 false
浮点数类型¶
- 浮点数没有实现
Eqtrait,因此不能直接用==和!=来比较,也不能作为字典的键。 - 数学上无定义的运算,如
0.0 / 0.0,Rust会返回NaN(Not a Number)。与NaN的运算结果总是NaN,并且NaN不能参与比较运算。 - 由于
NaN的存在,浮点数没有实现Ordtrait,因此不能直接用于sort()等需要Ordtrait的方法,需要用partial_cmp().unwrap()来进行比较。 - 由于浮点数的精度问题,浮点数的比较应该用
abs()和<、>来进行。
浮点数类型有如下方法:
is_nan():判断是否为NaN。
字符串字面量类型¶
字符串字面量类型有如下方法:
-
len():返回字符串长度。let s = "hello"; println!("{}", s.len()); // 5 -
lines():按换行符\n分割字符串,返回迭代器。let s = "hello\nworld"; for line in s.lines() { println!("{}", line); } -
split():按给定字符分割字符串,返回迭代器。let s = "hello world"; for word in s.split(" ") { println!("{}", word); } -
trim():去除字符串首尾的空白字符。let s = " hello world "; println!("{}", s.trim()); // "hello world" -
parse():将字符串转换为其他类型,如parse::<i32>()将字符串转换为i32类型。当转为数字时,数字不能超过类型的取值范围,否则会报错。let s = "123"; let n: i32 = s.parse().unwrap(); // 返回值是`Result`类型自定义类型如果需要通过
parse()转换为字符串,需要实现std::str::FromStrtrait,参见Impl & Trait -
to_string():将字符串字面量转换为String类型。 chars():返回字符串的字符迭代器。bytes():返回字符串的字节迭代器。
字符串类型¶
字符串类型有如下方法:
push()、push_str():分别用于在字符串末尾添加字符和字符串字面量。insert()、insert_str():分别用于在字符串中的指定位置插入字符和字符串字面量。replace(A, B)、replacen(A, B, n):分别用于将字符串中的A替换为B,replacen还可以指定替换次数n,返回替换后的新字符串。replace_range(range, A):用于将原字符串的指定范围替换为新的字符串A,返回替换后的原字符串。pop():删除并返回字符串末尾的字符,如果字符串为空则返回None。remove():删除并返回字符串中指定位置的字符。给定的索引必须是有效的字符边界。truncate():删除从指定位置开始到字符串结尾的全部字符。clear():清空字符串。+运算符:用于连接两个字符串,右端项为&str类型。
数组类型¶
数组越界
Rust会检查数组访问越界问题。
数组类型有如下方法:
-
std::array::from_fn():根据函数返回值生成数组。let a: [String; 8] = std::array::from_fn(|_i| String::from("This is Rust"));
迭代器类型¶
迭代器类型有如下方法:
-
map(fn):对迭代器中的每个元素应用函数fn,返回新的迭代器。let v = vec![1, 2, 3]; for i in v.iter().map(|x| x * 2) { print!("{}", i); // 246 } -
collect():将迭代器转换为容器(定长数组)。let v = vec![1, 2, 3]; let v2: Vec<i32> = v.iter().map(|x| x * 2).collect();
运算符¶
Rust的运算符与C/C++类似
- 四则运算符:
+ - * / % - 比较运算符:
== != > < >= <= - 逻辑运算符:
&& || ! - 位运算符:
& | ^ << >> !(!为按位取反) - 原位赋值运算符:
+= -= *= /= %= &= |= ^= <<= >>=等 - 类型转换运算符:
as,如let b = (a as f64) / 2.0; - 引用与解引用运算符:
& &mut *,其中&用于获取变量的引用(borrow),&mut用于获取变量的可变引用,*用于解引用。