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
声明的数组才能修改其中元素。- 注意不支持
Copy
trait的类型不能用[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
浮点数类型¶
- 浮点数没有实现
Eq
trait,因此不能直接用==
和!=
来比较,也不能作为字典的键。 - 数学上无定义的运算,如
0.0 / 0.0
,Rust会返回NaN
(Not a Number)。与NaN
的运算结果总是NaN
,并且NaN
不能参与比较运算。 - 由于
NaN
的存在,浮点数没有实现Ord
trait,因此不能直接用于sort()
等需要Ord
trait的方法,需要用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::FromStr
trait,参见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
用于获取变量的可变引用,*
用于解引用。