0. 前言
这是一个关于Rust的简单总结。(待续)
资料
Rust介绍
[[Rust]] 程序设计语言的本质实际在于 赋能(empowerment):无论你现在编写的是何种代码,Rust 能让你在更为广泛的编程领域走得更远,写出自信。(这一点并不显而易见)
Cargo介绍
[[Cargo]] 是 Rust 的构建系统和包管理器。大多数 Rustacean 们使用 Cargo 来管理他们的 Rust 项目,因为它可以为你处理很多任务,比如构建代码、下载依赖库并编译这些库。
1. Hello World!
Rust
- 编译
main.rs
文件 :rustc main.rs
- 运行
main.exe
程序 :main.exe
Cargo
- 新建 Cargo程序 :
Cargo new
Project Name
- 构建 Cargo程序:
Cargo build
- 构建并运行Cargo程序:
Cargo run
2. 变量可变性
- 不可变变量
let x = 5;
- 可变变量
let mut x = 5;
- 常量
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
3. 数据类型
标量类型
- 整数型 :
let x: u32 = 1;
- 浮点型 :
let x: f32 = 3.0;
注:f32
:单精度浮点数,f64
:双精度浮点数 - 字符类型 :
let x:char = 'ℤ';
- 布尔型 :
let x: bool = false;
注:Ture
,False
复合类型
- 元组型(Tuple):
let tup: (i32, f64, u8) = (500, 6.4, 1);
元组的使用:
let x = (500, 6.4, 1);
let five_hundred = x.0;
x.0
的值为500
let one = x.2;
- 数组型(array):
let a = [1, 2, 3, 4, 5];
数组的使用:
let a = [1, 2, 3, 4, 5];
let a:[i32; 5] = [1, 2, 3, 4, 5];
指定数组的类型和长度
let x = a[0]
a[0]
的 值为1
4.函数
表达式
//Rust中的表达式是指由{ }包裹的语句。
fn main(){
let y = {
let x = 3;
x + 1 //注意 `x+1` 这一行在结尾没有分号
};
println!("The value of y is: {y}");
}
函数
//返回值的函数
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1 //这里没有分号 ,函数体{}内是一个表达式,表达式的值作为函数的返回值
}
注:函数的参数必须指定数据类型 ,函数值利用表达式语法,表达式的值作为函数的返回值。
5.控制流
IF语句
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4"); }
else if number % 3 == 0 {
println!("number is divisible by 3"); }
else if number % 2 == 0 {
println!("number is divisible by 2"); }
else {
println!("number is not divisible by 4, 3, or 2"); }
WHILE语句
while number != 0 { println!("{number}!"); number -= 1; }
FOR语句
let a = [10, 20, 30, 40, 50];
for element in a { println!("the value is: {element}"); }
LOOP语句
loop
语句,无条件一直循环,通过输入Ctrl + C
终止条件。
loop { println!("again!"); }
break
关键字传参
let mut counter = 0;
loop {
counter += 1;
if counter == 10 {
break counter * 2; // break关键字传递参数
}
};
break
关键字标记
//break标记
fn main() {
let mut count = 0
'counting_up: loop {//标记处
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 { break; }//没有标记,跳出的是当前loop
if count == 2 { break 'counting_up; }//通过标记 跳出的是最外层loop
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
6.所有权
所有权:
- Rust中每一个值都有一个所有者(owner)。
- 值在任一时刻有且仅有一个所有者。
- 当所有者离开作用域时,这个值会被丢弃。
栈(Stack)与堆(Heap)
栈:存放的数据都必须占用已知且固定的大小。
堆:存放的数据大小未知或大小可能变化的数据。
数据交互方式
移动:
let x = 5; //x的值是放入了栈中的。
let y = x; //数据移动时,简单数据类型x不会失效。(复制了一份数据)
let s1 = String::from("hello"); //s1的值是存在堆中的。
let s2 = s1; //数据移动时,s1的值给了s2,s1失效。(堆中数据不会复制)
克隆:
let s1 = String::from("hello"); //s1的值是存在堆中的。
let s2 = s1.clone();//数据克隆,s1的值在堆中复制了一份,s1有效。
所有权与函数与返回值
fn main{
let s = String::from("hello"); //s 进入作用域
takes_ownership(s); //s 的值移动到函数里
let x = 5; //s 进入作用域
makes_copy(x); //x应该移动函数里,但 i32是Copy的,
//所以后面可以继续使用x
}//这里,x先移出了作用域,然后是s。但因为s的值已被移走。
fn main{
let s1 = gives_ownership(); //gives_ownership 将返回值转移给s1
let s2 = String::from("hello");//s2进入作用域
let s3 = takes_and_gives_back(s2);//s2 被移动到 takes_and_gives_back函数中
//它将返回值给s3。
}//这里,s3移出作用域并被丢弃,s2也将移动作用域,但已经被移走,所以什么也不会发生,s1离开作用域被丢弃。
引用与借用
- 引用:
&
例:let len = calculate_length(&s1);
- 解引用:
*
- 借用:创建引用的行为称为借用,借用不会获取其所有权。(离开作用域时,指向的值不会被丢弃。)
- 可变引用:
let mut s = String::from("hello")
let r1 = &mut s; //创建一个内容可以被改变的引用
- 引用的规则:
- 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
- 引用必须总是有效的。
字符串slice
let s = String::from("hello world");
let hello =&s[0..5]; // 对于字符串的部分引用。 [0..5] 也可以写成[..5]
let world = &s[6..11]; //[6..len] 也可以写成 [6..]
7.结构体
结构体示例
//User的结构体
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let mut user1 = User {
active: true,
username: String::from("someusername123"),
email:String::from("[email protected]"),
sign_in_count: 1,
}; //此处 是结构体User的一个实例
user1.email = String::from("[email protected]");
//此处是对实例的一个使用,更改实例User1里email成员的值。
}
使用字段初始化简写语法
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
// build_user 函数使用了字段初始化简写语法,因为 username 和 email 参数与结构体字段同名
fn build_user(email: String, username: String) -> User {
User {
active: true,
username,
email,
sign_in_count: 1,
}
}
fn main() {
let user1 = build_user(
String::from("[email protected]"),
String::from("someusername123"),
);
}
使用结构体更新语法从其他实例创建实例
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let user1 = User {
email: String::from("[email protected]"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
//这里 user2直接从user1的实例中取得了部分的数据。
let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("[email protected]"),
sign_in_count: user1.sign_in_count,
};
}
无命名字段结构体
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}
注:虽然这
Color
和Point
类型都由三个i32
值组成,但是一个获取Color
类型参数的函数不能接受Point
作为参数。因为它们是不同的元组结构体的实例。
结构体中的方法
- 关联函数:使用
impl
关键字将函数与结构体绑定,这些函数被称作结构体的关联函数。(注:关联函数经常被用作返回一个结构体新实例的构造函数,如new()
,类似于Java,C++中的静态方法。) - 方法:关联函数的第一个参数是
self
的函数被称作方法。
关联函数的使用:结构体名
::
关联函数名(
参数)
。
示例:let sq = Rectangle::square(3);
方法的使用:实例名
.
方法名(
参数)
示例:rect1.area()
关联函数示例:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
//这里 square 的第一个参数不是self,因此是关联函数。
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}
fn main() {
let sq = Rectangle::square(3);//关联函数的使用
}
方法的示例:
//这是一个结构体
struct Rectangle {
width: u32,
height: u32,
}
// impl:impl块中的内容都与Rectangle相关联。
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!(
"The area of the rectangle is {} square pixels.",
rect1.area() //这里,使用了rect1的area()方法。
);
}
X. 相关表
整数型相关
长度 | 有符号 | 无符号 |
---|---|---|
8-bit | i8 |
u8 |
16-bit | i16 |
u16 |
32-bit | i32 |
u32 |
64-bit | i64 |
u64 |
128-bit | i128 |
u128 |
arch | isize |
usize |
数字字面值 | 例子 |
---|---|
Decimal (十进制) | 98_222 |
Hex (十六进制) | 0xff |
Octal (八进制) | 0o77 |
Binary (二进制) | 0b1111_0000 |
Byte (单字节字符)(仅限于u8 ) |
b'A' |