关于Rust的简单总结(一)

发布时间 2023-12-12 19:20:24作者: TianyiLi-Tone

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; 注: TureFalse

复合类型

  • 元组型(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("someone@example.com"),
	sign_in_count: 1,
	 }; //此处 是结构体User的一个实例

	user1.email = String::from("anotheremail@example.com");
	//此处是对实例的一个使用,更改实例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("someone@example.com"),
        String::from("someusername123"),
    );
}

使用结构体更新语法从其他实例创建实例

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}
fn main() {
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    //这里  user2直接从user1的实例中取得了部分的数据。
    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@example.com"),
        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);
}

注:虽然这ColorPoint类型都由三个 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'