前言
2022,越來越多的公司開始用Rust
來重構項目了,如微軟重構windows
內核,rust
成為Linux
內核驅動的最佳支持語言,馬斯克的X
公司也用Rust
重構人工智能,Boss
的招聘條件開始加上會Rust優先
,越來越多的愛碼仕
們也在悄咪咪地練習borrow checker
,某天要是看見同事對著屏幕發飆:什么玩意兒,不倒騰了!,沒錯!也許他正在學習Rust
的路上。
如何打印打印
Rust 入門從打印開始,通常可使用println!
宏在標準 IO 輸出顯示。使用非常簡單,只可在占位符{}
的位置輸出對應的變量的值。
fn main() {
// Hello, world!
println!("Hello, world!");
println!("number: {} string: {}", 1, "hello");
}
基本數據類型
Rust 的基本類型與 C/C++非常相似,但命名變量類型名更加精確,非常容易知曉變量所占的內存空間大小。基本類型有:
i8, i16, i32, i64, i128, f32, f64, bool
u8, u16, u32, u64, u128
fn main() {
// 定義一個 u8 類型
let val: u8 = 0xff;
// 定義一個 u16 類型, 在一個代碼范圍內相同相同名字的變量,實際上不是上一個變量了,
let val: u16 = 0x1234;
// 定義一個 u32 類型, `_`符號認為該變量可能不會使用,因此編譯時不報警
let _val8: u32 = 0x12345648;
// 定義一個 u64 類型
let _val: u64 = 0x1234567812345678;
// 定義一個 u128 類型
let _val: u128 = 0x12345678123456781234567812345678;
// 定義一個 i8 類型, 類型會自動推導出
let _val = 127 as i8;
// 定義一個 i32 類型,類型會自動推導出
let _val = 250i32;
// 定義一個 i64 類型,類型會自動推導出
let _val = 123456_i64;
// 定義一個 i64 類型,類型會自動推導出
let _val = 1000_000_000 as i64;
// 定義一個 i128 類型, 類型會自動推導出
let _val = 1000_000_100_111 as i128;
// 定義一個 f64 類型,類型會自動推導出,浮點數默認為 f64類型
let _val = 1.001_33;
// 定義一個 f32 類型,類型會自動推導出
let _val = 1.010_33 as f32;
// 定義一個字符串切片
let _num = "123";
// 將字符串切片解析為 i32 類型
let _num: i32 = _num.parse().unwrap();
// 定義一個字符串
let _num = String::from("456.6");
// 將字符串解析為 f32 類型
let _num = _num.parse::().unwrap();
// 為 u32 類型重新定義一個別名
type U32 = u32;
let _val: U32 = 0x1234;
let _val = 0x1234 as U32;
// 定義一個 f32 的浮點數
let _vf32: f32 = 3.14;
// 浮點數默認為 f64 類型
let _vf64 = 3.14;
}
結構體、枚舉、元組
Rust
的 結構體和枚舉非常靈活,struct
內部的屬性能指定為任意類型,如普通的基本類型,枚舉等,甚至零大小類型。enum
也非常靈活,在C/C++
的基礎上,增加類型附帶的值,能非常直接得描述對象的邏輯,提供了抽象能力,然而并不會帶來內存或效率的損耗。元組類型通常用在一些對屬性名不重要的場合,類似Python
中元組的概念。參考以下代碼了解Rust
的struct
和enum
和元組的特點。
use std::mem::size_of;
use std::mem::size_of_val;
// 定義一個 Man 的結構體,包含兩個變量
mod people{
use crate::Gender;
// 定義一個 Man 的結構體,指定為 pub 屬性
pub struct Man{
// 定義 age 屬性,指定為私有屬性,模塊外不能訪問
age: u32,
// 定義 name 屬性,指定為 pub 屬性,模塊外能直接訪問
pub name: String,
// 定義 gender 屬性,指定為 pub
pub gender: Gender,
}
// 構造一個 pub 函數, 使用該函數生成 Man 對象
pub fn new_man(age: u32, name: &str, gender: Gender) -> Man{
Man{
age: age,
name: name.to_string(),
gender: gender
}
}
}
// 定義一個 Mode 的結構體,內部 mode 的屬性為模板 T 指定
struct Mode{
mode: T,
}
// 定義一個 Water 的結構體,大小為0
struct Water;
// 定義 Gender 枚舉,有三個屬性
enum Gender {
Man,
Femel,
Others,
}
#[derive(Debug)]
enum Color{
Red = 0xff0000,
Green = 0x00ff00,
Others
}
// 定義一個 Pregnant 的枚舉,只有一個屬性,屬性中附帶一個 i8 的變量,
// 表示 Baby 的數量
enum Pregnant{
Baby(i8),
}
// 定義一個 Fruit 的枚舉, 內部包含的屬性,附帶 T 類型的數據
enum Fruit{
Apple(T),
Grape(T)
}
struct Tuple(i8, i32, String, Color);
fn main() {
let man = people::new_man(20, "hunter", Gender::Man);
println!("man's name: {}", man.name);
// age 是私有變量,不能在模塊外面訪問
// println!("man's age: {}", man.age);
let mode:Mode = Mode { mode: true };
println!("mode: {}", mode.mode);
// 構造一個 water 的變量,并打印變量的大小
let water = Water;
println!("Water size: {}", size_of_val::(&water));
println!("Water size: {}", size_of::());
// 構造一個 Gender 的枚舉變量,并初始化值
let gender = Gender::Man;
println!("gender size: {}", size_of_val::(&gender));
// 構造一個 Color 的枚舉變量,并初始化值
let color = Color::Red;
println!("Color size: {}", size_of_val::(&color));
// 構造一個 Pregnant 的枚舉,并初始化值
let baby = Pregnant::Baby(2);
let Pregnant::Baby(number) = baby;
println!("Enum Pregnant size: {}", size_of_val::(&baby));
println!("baby: {}", number);
// 構造一個 Fruit 的枚舉值,并初始化值
let apple: Fruit = Fruit::Apple(Color::Red);
// 根據 內部值的類型打印細節
match apple {
Fruit::Apple(c) => println!("Apple color: {:?}", c),
Fruit::Grape(c) => println!("Grape color: {:?}", c),
}
// 構造一個 元組,并打印
let tuple = Tuple(127, -1, "Tuple String".to_string(), Color::Red);
println!("tuple: {} {} {} {:?}", tuple.0, tuple.1, tuple.2, tuple.3);
}
在Rust
的枚舉中,非常重要的默認枚舉類型如Option
,Result
等也經常使用在日常開發中。
判斷
Rust
的條件判斷語句有if
、if-else
、if-else if-else
、match
、if let
等語句,與C/C++
最大的不同是,這些語句都能像函數一樣返回數據。參考如下實例簡單理解。
fn main() {
let result = true;
// if 后面無需增加括號(),但必須添加代碼塊符號{}
if result {
println!("Result is true");
}
else {
println!("Result is false")
}
let number = 4;
if number == 4{
println!("number == 4");
}
let count = 10;
// if 判斷里面只能為 bool 類型,不會針對數字隱式轉換
// if count { // count 是 i32 類型, 不是 bool 類型,所以會編譯報錯
if count > 0 {
println!("count > 0");
}
// if 語句可以返回數值,類似 C/C++ 的三元操作: bool r = true? false: true;
let _r = if result == true {
false
}
else {
true
};
// match 類似 C/C++ 的switch 語句,但是match 要求必須完全枚舉所以得可能,否則編譯報錯
// match 匹配也可以返回一個值,可以使用也可以省略返回的
let r = match count {
// 匹配轉向符為 => 末尾添加,
10 => println!("count is 10"),
// 必須匹配剩余的可能性
_v => println!("count is {}", _v),
};
let r: Option = Some(1);
// if let 語句,根據匹配結果取出內部的數據
if let Some(v) = r {
println!("Some: {}", v)
}
}
循壞
Rust的循壞語句也非常豐富,常用的有loop``while``for,特殊一點的有wile let,非常實用,參考如下代碼簡單了解特性
fn main() {
let arr: [i32; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for v in arr {
println!("{}", v);
}
let mut max = i32::MAX;
for i in 0..arr.len() {
if max < arr[i] {
max = arr[i];
}
};
let mut idx = 0;
let len = loop {
if idx < arr.len(){
println!("{}", arr[idx]);
idx = idx + 1
}
else {
break idx
}
};
let mut idx = 0;
while idx < arr.len() {
println!("{}", arr[idx]);
idx += 1;
}
let mut s = Some(1);
// 當 s 為some時候能進入循壞,否則不進入循壞
while let Some(i) = s {
println!("once");
s = None;
}
}
函數
Rust
的函數定義與C/C++
稍許不同,Rust
對函數定義和調用的順序不做要求,也無需預定義,使用關鍵字fn
表示為函數定義,返回使用->
指定,函數內部的返回使用return
關鍵字或最后執行的語句所帶的值作為返回值。同時像C++
一樣支持函數模板,但更加簡單易用。參考如下代碼了解函數定義的特性。
fn test(num: i32) -> i32 {
println!("val: {}", num);
num
}
fn max(v1: i32, v2: i32) -> i32 {
if v1 > v2 {
v1
}
else if (v1 == v2) {
return v1
}
else {
v2
}
}
// 定義簡單的重載函數,生成同不的類型的參數的函數
fn fun(t: T) {
}
// ! 表示該函數永遠也不會返回
fn infinite() ->!{
loop {
}
}
fn main() {
let _t1 = test(1);
let _max = max(1, 2);
fun::(1);
fun::<&str>("1");
infinite()
}