Rust语言学习 02 开始
准备开始学习一门新的语言Rust
语言规范
编译器
rustc
- 跨平台
- 支持交叉编译
- 使用LLVM作为编译器后端
- Rust开发
- 对Rust源码进行分析检查后翻译为LLVM IR
- 输出错误信息友好和详尽
$ rustc --version
rustc 1.48.0 (7eac88abb 2020-11-16)
LLVM
核心库
标准库的基础,不依赖于操作系统和网络等相关的库,不知道堆分配,也不提供并发与IO
标准库
技术跨平台支持
包管理器
包(crate)可理解为一个项目
第三方包(库)
$ cargo new bin_crate
$ cargo new --lib lib_crate
编译
$ cargo build
$ cargo b
$ cargo build --release
$ cargo b --release
编译并运行
$ cargo run
$ cargo r
语句与表达式
不可变绑定与可变绑定
let关键字用于绑定,绑定是建立标识符和值之间的关联关系。 比如变量和常量,其中变量的值是可变的对应可变绑定,而常量的值是不可变的对应于不可变绑定。
fn main() {
let a1 = 1;
a1 += 1; // 错误,因为a1是不可变绑定,所以在此试图对其值的修改是错误的。
let mut a2 = 2;
a2 += a1; // 正确,a2为可变绑定。
println!("{}", a1);
println!("{}", a2);
}
error[E0384]: cannot assign twice to immutable variable `a1`
--> src/main.rs:3:5
|
2 | let a1 = 1;
| --
| |
| first assignment to `a1`
| help: make this binding mutable: `mut a1`
3 | a1 += 1;
| ^^^^^^^ cannot assign twice to immutable variable
所有权与错用
fn print_type_of< T >(_: &T) {
println!("{}", std::any::type_name::< T >())
}
fn main() {
let s1 = "hello 1";
let s2 = "hello 2".to_string();
print_type_of(&s1);
print_type_of(&s2);
let o = s1;
print_type_of(&o);
println!("{:?}", s1);
let o = s2;
print_type_of(&o);
println!("{:?}", s2);
}
error[E0382]: borrow of moved value: `s2`
--> src/main.rs:16:22
|
7 | let s2 = "hello 2".to_string();
| -- move occurs because `s2` has type `String`, which does not implement the `Copy` trait
...
14 | let o = s2;
| -- value moved here
15 | print_type_of(&o);
16 | println!("{:?}", s2);
| ^^ value borrowed here after move
函数与闭包
作用域与生命周期
fn main() {
let v = "hello world!";
assert_eq!(v, "hello world!");
let v = "hello Rust!"; // 对同一变量进行绑定的做法叫变量遮蔽,值以最新的绑定为准。
assert_eq!(v, "hello Rust!");
{
let v = "Hello World!"; // 这个v变量的作用域和生命周期被限制在这个大扩号内。
assert_eq!(v, "Hello World!");
}
assert_eq!(v, "hello Rust!");
}
函数指针
Rust语言中,函数被称为一等公民。这意味着,函数自身就可以作为函数的参数和返回值使用。
pub fn math(op: fn(i32, i32) -> i32, a: i32, b: i32) -> i32 {
return op(a, b);
}
fn sum(a: i32, b: i32) -> i32 {
return a + b;
}
fn product(a: i32, b: i32) -> i32 {
return a * b;
}
fn main() {
let a = 2;
let b = 3;
assert_eq!(math(sum, a, b), 5); // sum和product是被做为参数的函数
assert_eq!(math(product, a, b), 6);
}
函数作为返回值的例子
fn is_true() -> bool { true } // 作为返回值的函数
fn true_maket() -> fn() -> bool { is_true } // 返回值是函数的函数
fn main() {
assert_eq!(true_maket()(), true);
}
CTFE机制
编译时函数执行(Compile-Time Function Execution, CTFE)
const fn init_len() -> usize {
return 9;
}
fn main() {
let arr = [0; init_len()];
// 通过[0; N]这种形式来初始化一个初始值为0,长度为N的数组。其中长度N必须在编译期知道值,否则编译出错。所以init_len必须在编译期求值。
println!("{:?}", arr);
}
闭包
流程控制
条件表达式
fn main() {
let n = 13;
let big_n = if n < 10 && n > -10 {
10 * n
}
else {
n / 2
};
assert_eq!(big_n, 6);
}
循环表达式
Rust有三种循环表达式: while, loop 和 for…in
下面以Fizz Buzz问题实现举例
给你一个整数n. 从 1 到 n 按照下面的规则打印每个数: 如果这个数被3整除,打印fizz. 如果这个数被5整除,打印buzz. 如果这个数能同时被3和5整除,打印fizz buzz.
- while
fn main() {
let mut n = 1;
while n < 101 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
n += 1;
}
}
- loop
fn main() {
let mut n = 1;
loop {
if n > 100 { break; }
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
n += 1;
}
}
- for…in
n >= 1 && n < 101
fn main() {
for n in 1..101 {
if n % 13 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
- 无限循环
务必使用loop,避免使用while true。
match表达式与模式匹配
match类似于其它语言中的swatch或case。
fn main() {
for number in 0..43 {
match number {
0 => println!("{} Origin", number),
1..=3 => println!("{} All", number), // 区间
| 5 | 7 | 13 => println!("{} Bad Luck", number), // 或
n @ 42 => println!("Answer is {}", n), // @符可以将模式中的值绑定给一个变量
_ => println!("{} Common", number), // default
}
}
}
match分支使用了模式匹配,分支左边是模式,右边是执行代码。
if let和while let表达式
用于某些场合下替代match表达式,左侧为模式,右侧为要匹配的值。
基本数据类型
布尔类型
bool = true / false
不支持将数字转换为bool类型
数字类型
u8,u16,u32,u64,u128
i8, i16, i32, i64, i128
usize, isize
f32, f64
字符类型
使用单引号来定义字符。