系列综述:
目的:本系列是个人学习Rust语言整理的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
来源:材料主要源于b站的Rust中文社群线上学习室和菜鸟教程
进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
结语:如果有帮到你的地方,就点个赞和关注一下呗,谢谢!!!
点此到文末惊喜↩︎
let
将值和变量名进行绑定,声明同时必须初始化// 不可变绑定
let x = 5;// 绑定同时必须初始化
x = 10; // error: 绑定后不能改变
// 强类型的自动推导
let x = 1.000;// 编译器会推断为f32
let x : f64 = 1.000;// 类型注解
mut
表示可变绑定// 普通的mut可变
let mut x = 5;
x = 10;
// 变量遮蔽的继承可变
let x = 5; // warning:未使用的符号
let x = 10;// 可以通过let对同一符号名进行重新绑定
强类型语言
,能类型推导和进行类型安全检查类型注解
,没有注解Rust会进行类型推断,可能不符合预期内存安全
考虑,不允许使用或捕获任何未初始化的变量位置表达式 = 值表达式
,Rust没有左右值的概念,左边表达式返回内存地址,右边表达式返回值const NUMBER:i32 = 3;
位长度 | 有符号 | 无符号 |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
fn main() {
let x = 2.0; // 默认浮点数类型推导为f64
let y: f32 = 3.0; // f32
}
let tup: (i32, f64, u8) = (500, 6.4, 1);
// tup.0 等于 500
// tup.1 等于 6.4
// tup.2 等于 1
let (x, y, z) = tup;
// y 等于 6.4
// a 是一个长度为 5 的整型数组
let a = [1, 2, 3, 4, 5];
// b 是一个长度为 3 的字符串数组
let b = ["January", "February", "March"];
// c 是一个长度为 5 的 i32 数组
let c: [i32; 5] = [1, 2, 3, 4, 5];// [类型;长度]
// 等同于 let d = [3, 3, 3, 3, 3];
let d = [3; 5];
// 数组访问
let first = a[0];
let second = a[1];
a[0] = 123; // 错误:数组 a 不可变
let mut a = [1, 2, 3];
a[0] = 4; // 正确
/// 常用作文档的开头
// 这是第一种注释方式
/* 这是第二种注释方式 */
/*
* 多行注释
* 多行注释
* 多行注释
*/
fn 函数名 ( 参数 ) {函数体}
// 主函数
fn main() {
call_me(5);
}
// 子函数
fn call_me(num: u32) {// 参数必须类型声明
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
fn call_me(num: u32)-> i32 {// ->表示返回值类型
num
}
if condition { block 1 } else { block 2 }
if a > b {// 没有括号
a
} else {
b
}
let number = if a > 0 { 1 } else { -1 };
//基本while循环
let mut i = 0;
while i < 10 {
// 循环体
i += 1;
}
// 范围for
let a = [10, 20, 30, 40, 50];
for i in a.iter() {
println!("{}", i);
}
// 下标for
let a = [10, 20, 30, 40, 50];
for i in 0..5 {
println!("a[{}] = {}", i, a[i]);
}
// 无限循环loop
let mut i = 0;
loop {
let ch = s[i];
if i == 5 {
break;
}
i += 1;
}
切片后字符串在堆的起始地址+长度
,堆上为被引用的字符串切片
和双引号的字符串
都是&str类型let s = String::from("broadcast");
let part1 = &s[0..5];// 0,1,2,3,4
// 参数只读的打印函数
fn greet(name: &str) {// 类似与const &形参
println!("Hello, {}!", name);
}
// 切片引用不能修改原值
let mut s = String::from("runoob");
let slice = &s[0..3];
s.push_str("yes!"); // 错误
let s1 = String::from("hello");
let s2 = &s1[..];// String 转换成 &str
let s3 = s2.tostring();
片开始指针 + 大小
..
,其中x…y 表示 [x, y) 的数学含义..y // 等价于 0..y
x.. // 等价于位置 x 到数据结束
.. // 等价于位置 0 到结束
x..y // x到y前闭后开
let arr = [1, 3, 5, 7, 9];
let part = &arr[0..3];
for i in part.iter() {
println!("{}", i);
}
// 直接初始化
let runoob = Site {
domain: String::from("www.runoob.com"),
name: String::from("RUNOOB"),
nation: String::from("China"),
found: 2013
};
// 初始化后组合
let domain = String::from("www.runoob.com");
let name = String::from("RUNOOB");
let runoob = Site {
domain, // 等同于 domain : domain,
name, // 等同于 name : name,
nation: String::from("China"),
traffic: 2013
};
..runoob
let site = Site {
domain: String::from("www.runoob.com"),
name: String::from("RUNOOB"),
..runoob
};
struct Color(u8, u8, u8);
struct Point(f64, f64);
let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);
{:#?}
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!("rect1 is {:?}", rect1);// 打印结构体的所有属性
}
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn wider(&self, rect: &Rectangle) -> bool {
self.width > rect.width
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 40, height: 20 };
println!("{}", rect1.wider(&rect2));
}
// 基本用法
enum Book {
Papery, Electronic
}
let book = Book::Papery;
// 枚举类属性增加描述
enum Book {
Papery(u32),
Electronic(String),
}
let book = Book::Papery(1001);
// 属性命名
enum Book {
Papery { index: u32 },
Electronic { url: String },
}
let book = Book::Papery{index: 1001};
enum Option<T> {
Some(T),
None,
}
let opt: Option<&str> = Option::None;
match opt {
Option::Some(something) => {
println!("{}", something);
},
Option::None => {
println!("opt is nothing");
}
}
// 输出opt is nothing
if let
if let 匹配值 = 源变量 {
语句块1
}else{
语句块2
}
// 示例
let i = 0;
if let 0 = i {
println!("zero");
}
// 输出zero
// second_module.rs 文件
pub fn message() -> String {
String::from("This is the 2nd module.")
}
// main.rs
mod second_module;
fn main() {
println!("This is the main module.");
println!("{}", second_module::message());
}
//输出This is the main module. This is the 2nd module.
use
引入模块,as
避免局部模块重名mod nation {
pub mod government {
pub fn govern() {}
}
pub use government::govern;
}
fn main() {
nation::govern();
}
RUST_BACKTRACE=1
环境变量运行以显示回溯"fn main() {
panic!("error occured");
println!("Hello, Rust");
}
// 输出
thread 'main' panicked at 'error occured', src\main.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
match f {
Ok(file) => {
println!("File opened successfully.");
},
Err(err) => {
println!("Failed to open the file.");
}
}
}
// 在 Result 为 Err 时调用 panic! 宏
let f1 = File::open("hello.txt").unwrap();
// 在 Result 为 Err 时调用 panic! 宏,并且可以输出一段指定信息
let f2 = File::open("hello.txt").expect("Failed to open.");
?
符仅用于返回值类型为 Resultuse std::io;
use std::io::Read;
use std::fs::File;
fn read_text_from_file(path: &str) -> Result<String, io::Error> {
let mut f = File::open(path)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let str_file = read_text_from_file("hello.txt");
match str_file {
Ok(s) => println!("{}", s),
Err(e) => {
match e.kind() {// kind函数用于判断 Result 的 Err 类型
io::ErrorKind::NotFound => {
println!("No such file");
},
_ => {// 其他情况
println!("Cannot read the file");
}
}
}
}
}
// 大小的比较
fn max<T>(array: &[T]) -> T {
let mut max_index = 0;
let mut i = 1;
while i < array.len() {
if array[i] > array[max_index] {
max_index = i;
}
i += 1;
}
array[max_index]
}
struct Point<T> {
x: T,
y: T
}
let p1 = Point {x: 1, y: 2};
let p2 = Point {x: 1.0, y: 2.0};
let p = Point {x: 1, y: 2.0};// error,推导类型不匹配
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("p.x = {}", p.x());
}
impl <特性名> for <所实现的类型名>
, 同一个类可以实现多个特性,但每个 impl 块只能实现一个。// 特性接口:实现类必须实现特性接口中的方法
trait Descriptive {
fn describe(&self) -> String;
}
// 类属性
struct Person {
name: String,
age: u8
}
// 类方法
impl Descriptive for Person {
fn describe(&self) -> String {
format!("{} {}", self.name, self.age)
}
}
// 基本使用
fn output(object: impl Descriptive) {
println!("{}", object.describe());
}
// 多类型
fn output_two<T: Descriptive>(arg1: T, arg2: T) {
println!("{}", arg1.describe());
println!("{}", arg2.describe());
}
let vector: Vec<i32> = Vec::new(); // 创建类型为 i32 的空向量
let vector = vec![1, 2, 4, 8]; // 通过数组创建向量
vector.push(16);// 在末尾追加单个元素
let mut v1: Vec<i32> = vec![1, 2, 4, 8];
let mut v2: Vec<i32> = vec![16, 32, 64];
v1.append(&mut v2);
let string = String::new();
let one = 1.to_string(); // 整数到字符串
let float = 1.3.to_string(); // 浮点数到字符串
let slice = "slice".to_string(); // 字符串切片到字符串
let mut hello = String::from("Hello");// 直接初始化成任何utf-8的字符串
s.push_str("oob"); // 追加字符串切片
s.push('!'); // 追加字符
// 拼接字符串
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;
// 用宏进行字符串改进
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
// 计算长度
let s = "你好";
let len = s.len();// 6个字节长度
// 遍历字符串
let s = String::from("hello中文");
for c in s.chars() {
println!("{}", c);
}
let mut map = HashMap::new();
map.insert("color", "red");// 键值对的插入
map.insert("size", "10 m^2");
println!("{}", map.get("color").unwrap());// 值的获取
map.entry("color").or_insert("red");// 如果没有键为 "color" 的键值对就添加它并设定值为 "red",否则将跳过
// second.rs
// 类的属性
pub struct ClassName {
field: i32,
}
// 类的方法
impl ClassName {
pub fn new(value: i32) -> ClassName {
ClassName {
field: value
}
}
pub fn public_method(&self) {
println!("from public method");
self.private_method();
}
fn private_method(&self) {
println!("from private method");
}
}
// main.rs
mod second;
use second::ClassName;
fn main() {
let object = ClassName::new(1024);// new一个对象
object.public_method();// 对象调用方法
}
方法
本质是面向对象机制下的函数
{
// 在声明以前,变量 s 无效
let s = "runoob";
// 这里是变量 s 的可用范围
}
// 变量范围已经结束,变量 s 无效
let s1 = String::from("hello");
let s2 = s1;
// 赋值后s1失效,指向的堆内存所有权移动给s2
let x = 5;
let y = x;
// 拷贝语义:赋值后均有效
// 堆内存的拷贝
let s1 = String::from("hello");
let s2 = s1.clone();
fn main() {
let s = String::from("hello");
// s 被声明有效
takes_ownership(s);
// s 的值被当作参数传入函数
// 所以可以当作 s 已经被移动,从这里开始已经无效
let x = 5;
// x 被声明有效
makes_copy(x);
// x 的值被当作参数传入函数
// 但 x 是基本类型,依然有效
// 在这里依然可以使用 x 却不能使用 s
let s2 = String::from("hello");
let s3 = takes_and_gives_back(s2);
// s2 被当作参数移动, s3 获得返回值所有权
} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放
fn takes_ownership(some_string: String) {
// 一个 String 参数 some_string 传入,有效
println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放
fn makes_copy(some_integer: i32) {
// 一个 i32 参数 some_integer 传入,有效
println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放
fn take_and_giveback(a_string:String)->String{
a_string // a_string 被当作返回值移出函数
}
// 基本引用
let s1 = String::from("hello");
let s2 = &s1;
// 所有权转移引起的租借失效
let s1 = String::from("hello");
let mut s2 = &s1;
let s3 = s1;// s1内存资源所有权转移到s3中,s2的租借失效
s2 = &s3; // 重新从 s3 租借所有权
// 可变租借
let mut s1 = String::from("run");// 被租借对象本身就是可变的
// s1 是可变的
let s2 = &mut s1;// 赋予租借者可变的权力
// s2 是可变的引用
let s3 = &mut s1;// error,不允许多重可变引用
fn main() {
let vec0 = Vec::new(); // 在堆上new一个vector
let mut vec1 = fill_vec(vec0);// 调用函数
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88); // 上面定义vec1必须是一个可变调用
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec;
// vector添加数据元素
vec.push(22); // 相当于Vec::push(&mut vec, 22),其中&mut vec为一个可变借用
vec.push(44);
vec.push(66);
vec// 无分号表达式的返回
}
Cargo new
创建的就是一个工程包,一个包最多包含一个库"箱",可以包含任意数量的二进制"箱",但是至少包含一个"箱",src 目录下会生成一个 main.rs 源文件,Cargo 默认这个文件为二进制箱的根。
// 默认是私有的,只有在与其平级的位置或下级的位置才能访问,不能从其外部访问。
mod nation {
pub mod government {
fn govern() {}
}
mod congress {
fn legislate() {}
}
mod court {
fn judicial() {}
}
}
// 从crate开始的绝对路径
crate::nation::government::govern();、
// 从其中任一个开始的相对路径
nation::government::govern();
'static
所表示的生命周期从程序运行开始到程序运行结束。// 标注生命周期的一致性
fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
fn main() {
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
println!("{} is longer", r);
}
}
fn main() {
let args = std::env::args();
println!("{:?}", args);
}
// 文件流的读取
use std::io::prelude::*;
use std::fs;
fn main() {
let mut buffer = [0u8; 5];
let mut file = fs::File::open("D:\\text.txt").unwrap();
file.read(&mut buffer).unwrap();
println!("{:?}", buffer);
file.read(&mut buffer).unwrap();
println!("{:?}", buffer);
}
// 文件写入
use std::io::prelude::*;
use std::fs::File;
fn main() {
let mut file = File::create("D:\\text.txt").unwrap();
file.write(b"FROM RUST PROGRAM").unwrap();
}
点此跳转到首行↩︎