Rust的基礎(chǔ)數(shù)據(jù)類型、變量系統(tǒng)、類型轉(zhuǎn)換以及實戰(zhàn)應(yīng)用
一、學習目標與重點
1.1 學習目標
- 掌握基礎(chǔ)數(shù)據(jù)類型:理解Rust所有標量類型(整數(shù)、浮點數(shù)、布爾值、字符)的定義、內(nèi)存布局、范圍限制與字面量寫法
- 精通復(fù)合類型:熟練運用元組(Tuple)、數(shù)組(Array)、切片(Slice)處理復(fù)雜數(shù)據(jù)結(jié)構(gòu),理解其固定/動態(tài)特性
- 理解變量系統(tǒng):深入掌握變量的聲明、可變性控制、作用域規(guī)則,以及Shadowing(變量隱藏)機制的應(yīng)用場景
- 熟練類型轉(zhuǎn)換:熟悉Rust嚴格的類型安全規(guī)則,掌握隱式轉(zhuǎn)換(極少)與顯式轉(zhuǎn)換(as關(guān)鍵字、From/Into Traits)的方法
- 實戰(zhàn)應(yīng)用:能結(jié)合真實場景運用基礎(chǔ)數(shù)據(jù)類型編寫簡單但實用的代碼,解決常見問題
1.2 學習重點
?? 三大核心難點:
- 整數(shù)類型的無符號/有符號區(qū)分與溢出處理機制
- 切片(Slice)的引用本質(zhì)與生命周期依賴(簡單引入,后續(xù)章節(jié)深入)
- Shadowing(變量隱藏)與
mut(可變性)的本質(zhì)區(qū)別
?? 三大高頻錯誤點:
- 浮點數(shù)精度問題導致的邏輯錯誤
- 數(shù)組越界訪問引發(fā)的編譯/運行時崩潰
- 錯誤使用類型轉(zhuǎn)換導致的未定義行為

二、Rust的基礎(chǔ)數(shù)據(jù)類型詳解
Rust的數(shù)據(jù)類型分為標量類型(單個值)和復(fù)合類型(多個值的組合),所有變量在編譯期必須明確類型(強靜態(tài)類型語言)。
2.1 標量類型
2.1.1 整數(shù)類型
Rust提供了10種整數(shù)類型,分為無符號整數(shù)(以u開頭,只能表示正數(shù)和0)和有符號整數(shù)(以i開頭,能表示正負整數(shù)),每種類型的位數(shù)從8位到128位不等。
?? 整數(shù)類型表:
| 長度(位) | 無符號類型 | 有符號類型 | 最小值 | 最大值 |
|---|---|---|---|---|
| 8 | u8 | i8 | 0 | 255 |
| 16 | u16 | i16 | -32768 | 32767 |
| 32 | u32 | i32 | -2³¹ | 2³¹-1 |
| 64 | u64 | i64 | -2?³ | 2?³-1 |
| 128 | u128 | i128 | -2¹²? | 2¹²?-1 |
| 平臺相關(guān) | usize | isize | 0 | 取決于CPU架構(gòu)(x86為2³²,x86_64為2??) |
?? 整數(shù)字面量寫法示例:
// 十進制(默認) let a = 10; // i32(默認) let b: u32 = 20; // 顯式類型注解 // 十六進制(0x開頭) let c = 0xff; // i32,255 let d: u8 = 0x1A; // 26 // 八進制(0o開頭) let e = 0o77; // i32,63 // 二進制(0b開頭) let f = 0b1010; // i32,10 // 字節(jié)字面量(u8,僅適用于ASCII) let g = b'A'; // u8,65 // 分隔符(_,增強可讀性) let h = 1_000_000; // i32,1000000
?? 整數(shù)溢出問題:
Rust在Debug模式(默認)下會檢查整數(shù)溢出,若發(fā)生溢出會直接崩潰(panic!);在Release模式下會默認啟用“兩補數(shù)環(huán)繞”(Wrapping)行為,但這是未定義行為(UB),建議顯式處理溢出。
?? 溢出處理方法示例:
// 使用checked_*方法,溢出時返回None
let x: u8 = 255;
match x.checked_add(1) {
Some(y) => println!("255 + 1 = {}", y),
None => println!("255 + 1 發(fā)生溢出"), // 會執(zhí)行這條
}
// 使用saturating_*方法,溢出時取最大值/最小值
let y: u8 = 255;
let z = y.saturating_add(1); // z = 255
// 使用wrapping_*方法,強制兩補數(shù)環(huán)繞
let w: u8 = 255;
let v = w.wrapping_add(1); // v = 0
2.1.2 浮點數(shù)類型
Rust提供了兩種浮點數(shù)類型:
f32:32位單精度浮點數(shù)(IEEE-754標準),精度約6-7位小數(shù)f64:64位雙精度浮點數(shù)(IEEE-754標準),精度約15-17位小數(shù)(默認類型)
?? 浮點數(shù)字面量寫法示例:
// 十進制小數(shù) let a = 3.14; // f64(默認) let b: f32 = 2.718; // 顯式類型注解 // 科學計數(shù)法 let c = 1e5; // f64,100000.0 let d: f32 = 2.5e-3; // 0.0025
?? 浮點數(shù)精度問題:
浮點數(shù)無法精確表示所有十進制小數(shù),會導致邏輯錯誤。
?? 精度問題示例:
let x = 0.1 + 0.2;
println!("0.1 + 0.2 = {}", x); // 輸出0.30000000000000004
println!("x == 0.3? {}", x == 0.3); // 輸出false
// 解決方法:比較差值是否小于一個極小值(epsilon)
fn float_equals(a: f64, b: f64) -> bool {
(a - b).abs() < 1e-9
}
println!("x == 0.3? {}", float_equals(x, 0.3)); // 輸出true
2.1.3 布爾類型
Rust的布爾類型只有bool一種,值只能是true或false,占用1字節(jié)內(nèi)存(確保內(nèi)存對齊)。
?? 布爾類型使用示例:
let is_true = true;
let is_false: bool = false;
// 布爾類型常用于條件判斷
if is_true {
println!("這是真的");
} else {
println!("這是假的");
}
// 布爾類型可以轉(zhuǎn)換為整數(shù)
let true_as_u8 = is_true as u8; // 1
let false_as_u8 = is_false as u8; // 0
2.1.4 字符類型
Rust的字符類型是char,占用4字節(jié)內(nèi)存,支持Unicode標量值(包括中文、日文、韓文、表情符號等,范圍是U+0000到U+10FFFF)。
?? 字符類型使用示例:
let a = 'A'; // 英文大寫字母,ASCII碼65
let b: char = '中'; // 中文,Unicode值U+4E2D
let c = '??'; // 表情符號,Unicode值U+1F600
// 字符類型可以轉(zhuǎn)換為整數(shù)
let a_as_u32 = a as u32; // 65
println!("'A'的Unicode值是U+{:X}", a_as_u32); // 輸出U+41
2.2 復(fù)合類型
2.2.1 元組類型
元組是固定長度、異質(zhì)數(shù)據(jù)類型的組合,長度在聲明時必須明確,且后續(xù)無法修改。
?? 元組聲明與訪問示例:
// 聲明元組
let t1: (i32, f64, bool) = (10, 3.14, true);
let t2 = ("hello", 'R', 2024); // 編譯器自動推斷類型
// 訪問元組元素
// 方法1:索引訪問(從0開始)
println!("t1的第0個元素:{}", t1.0); // 10
println!("t1的第1個元素:{}", t1.1); // 3.14
println!("t1的第2個元素:{}", t1.2); // true
// 方法2:解構(gòu)賦值
let (x, y, z) = t2;
println!("x = {}, y = {}, z = {}", x, y, z); // x = hello, y = R, z = 2024
// 單元素元組(必須加逗號)
let t3 = (5,); // 類型是(i32,)
let t4 = (5); // 這不是元組,而是整數(shù)5
// 空元組(單元類型,值只有一個())
let t5 = (); // 類型是(),常用于表示無返回值的函數(shù)
?? 元組作為函數(shù)返回值示例:
// 計算矩形的面積和周長
fn calculate_rectangle(width: u32, height: u32) -> (u32, u32) {
let area = width * height;
let perimeter = (width + height) * 2;
(area, perimeter) // 返回元組
}
fn main() {
let (area, perimeter) = calculate_rectangle(10, 5);
println!("面積:{},周長:{}", area, perimeter); // 面積:50,周長:30
}
2.2.2 數(shù)組類型
數(shù)組是固定長度、同質(zhì)數(shù)據(jù)類型的組合,存儲在棧內(nèi)存上,長度在聲明時必須明確,且后續(xù)無法修改。
?? 數(shù)組聲明與訪問示例:
// 聲明數(shù)組
let a: [i32; 3] = [1, 2, 3]; // 類型注解:[元素類型; 長度]
let b = [10, 20, 30]; // 編譯器自動推斷類型
let c = [5; 4]; // 初始化:每個元素都是5,長度為4
// 訪問數(shù)組元素
println!("a的第0個元素:{}", a[0]); // 1
println!("a的第2個元素:{}", a[2]); // 3
println!("c的第1個元素:{}", c[1]); // 5
// 獲取數(shù)組長度
println!("a的長度:{}", a.len()); // 3
// 數(shù)組遍歷
for element in a.iter() {
println!("{}", element); // 輸出1、2、3
}
// 可變數(shù)組
let mut d = [1, 2, 3];
d[0] = 10; // 修改第0個元素
println!("d的第0個元素:{}", d[0]); // 10
?? 數(shù)組越界訪問問題:
Rust在編譯期無法檢查所有越界訪問,但在運行期會檢查,若發(fā)生越界會直接崩潰(panic!)。
?? 越界訪問示例:
let a = [1, 2, 3];
println!("a的第3個元素:{}", a[3]); // 運行期崩潰:index out of bounds: the len is 3 but the index is 3
2.2.3 切片類型
切片是數(shù)組或Vec(動態(tài)數(shù)組)的動態(tài)視圖,存儲在棧內(nèi)存上,包含兩個部分:
- 指向數(shù)組/Vec的指針(*const T 或 *mut T)
- 切片的長度(usize)
?? 核心特性:
- 切片本身不存儲數(shù)據(jù),它只是一個引用
- 切片的長度在運行期可以動態(tài)變化,但不能超過原數(shù)組/Vec的長度
- 切片的類型是
&[T](不可變切片)或&mut [T](可變切片)
?? 切片聲明與訪問示例:
// 不可變數(shù)組切片
let a = [1, 2, 3, 4, 5];
let slice1 = &a[1..3]; // 從索引1到索引3(不包含3),元素是[2, 3]
let slice2 = &a[..2]; // 從開頭到索引2(不包含2),元素是[1, 2]
let slice3 = &a[3..]; // 從索引3到結(jié)尾,元素是[4, 5]
let slice4 = &a[..]; // 整個數(shù)組,元素是[1,2,3,4,5]
// 訪問切片元素
println!("slice1的第0個元素:{}", slice1[0]); // 2
println!("slice1的長度:{}", slice1.len()); // 2
// 可變數(shù)組切片
let mut b = [1, 2, 3, 4, 5];
let mut_slice = &mut b[1..3];
mut_slice[0] = 20; // 修改切片的第0個元素,也就是原數(shù)組的第1個元素
println!("原數(shù)組b:{:?}", b); // 輸出[1,20,3,4,5]
// Vec的切片(與數(shù)組切片類似)
let mut vec = vec![10, 20, 30, 40, 50];
let vec_slice = &vec[2..4];
println!("Vec切片:{:?}", vec_slice); // [30,40]
2.3 字符串類型
Rust的字符串類型分為兩種,初學者容易混淆:
- &str:不可變字符串切片,存儲在靜態(tài)內(nèi)存(如字符串字面量)或棧內(nèi)存(指向其他字符串的切片)上,類型是
&str - String:可變性字符串,存儲在堆內(nèi)存上,類型是
String
?? 字符串類型使用示例:
// 字符串字面量(&str)
let s1: &str = "Hello, Rust!"; // 存儲在靜態(tài)內(nèi)存上
let s2 = "這是中文"; // 編譯器自動推斷類型為&str
// String類型的創(chuàng)建
let s3 = String::new(); // 創(chuàng)建空字符串
let s4 = String::from(s1); // 從&str創(chuàng)建String
let s5 = String::from("動態(tài)字符串"); // 直接創(chuàng)建
// 字符串連接
let s6 = s4 + " " + s5.as_str(); // 注意:s4被轉(zhuǎn)移所有權(quán),s5需要.as_str()轉(zhuǎn)換為&str
println!("s6:{}", s6); // 輸出Hello, Rust! 動態(tài)字符串
// 不可變字符串連接(保留所有變量的所有權(quán))
let s7 = format!("{} {} {}", s1, s5, 2024);
println!("s7:{}", s7); // 輸出Hello, Rust! 動態(tài)字符串 2024
// 字符串切片(按字節(jié)索引,注意:Rust的字符串是UTF-8編碼的,一個中文字符占3字節(jié))
let s8 = "Rust語言開發(fā)";
println!("s8的第0-3字節(jié):{}", &s8[0..3]); // Rust
// println!("s8的第4-5字節(jié):{}", &s8[4..6]); // 編譯期崩潰:byte index 4 is not a char boundary
// 獲取字符串的字符迭代器(按字符索引)
for c in s8.chars() {
println!("{}", c); // 輸出R、u、s、t、語、言、開、發(fā)
}
2.4 變量系統(tǒng)
2.4.1 變量聲明
Rust的變量聲明必須使用let關(guān)鍵字,變量默認是不可變的(immutable)。
?? 變量聲明示例:
// 簡單聲明(編譯器自動推斷類型)
let x = 10;
let y = "hello";
// 顯式類型注解
let z: u8 = 255;
let w: String = String::from("Rust");
2.4.2 變量的可變性
如果需要修改一個變量,必須在聲明時添加mut關(guān)鍵字(mutable)。
?? 可變變量示例:
let mut x = 10;
x = 20;
println!("x:{}", x); // 輸出20
let mut s = String::from("hello");
s.push_str(", Rust!");
println!("s:{}", s); // 輸出hello, Rust!
2.4.3 變量的作用域
變量的作用域是從聲明位置到所在代碼塊({})的結(jié)束位置。
?? 變量作用域示例:
fn main() {
let x = 10; // x的作用域開始
{
let y = 20; // y的作用域開始
println!("x + y = {}", x + y); // 30,x可以訪問,y可以訪問
} // y的作用域結(jié)束
// println!("y = {}", y); // 編譯錯誤:y未聲明
println!("x = {}", x); // 10,x的作用域未結(jié)束
} // x的作用域結(jié)束
2.4.4 Shadowing(變量隱藏)
Shadowing是指在同一作用域或嵌套作用域內(nèi),用相同的變量名聲明一個新變量,新變量會隱藏舊變量。
?? Shadowing示例:
// 同一作用域內(nèi)的Shadowing
let x = 10;
let x = x + 5; // 新變量x隱藏舊變量x,類型仍然是i32,值是15
println!("x:{}", x); // 15
// 嵌套作用域內(nèi)的Shadowing
let y = 20;
{
let y = "hello"; // 新變量y隱藏舊變量y,類型是&str
println!("內(nèi)部y:{}", y); // hello
}
println!("外部y:{}", y); // 20,舊變量y重新可見
// Shadowing與類型轉(zhuǎn)換結(jié)合
let z = "123";
let z = z.parse::<i32>().unwrap(); // 新變量z隱藏舊變量z,類型是i32,值是123
println!("z:{}", z); // 123
?? Shadowing vs mut:
| 特性 | Shadowing | mut |
|---|---|---|
| 變量名 | 可以相同 | 可以相同 |
| 變量類型 | 可以不同 | 必須相同 |
| 內(nèi)存地址 | 可能不同 | 必須相同 |
| 作用域 | 同一或嵌套作用域 | 同一作用域 |
| 適用場景 | 需要類型轉(zhuǎn)換或重新計算 | 需要修改值但類型不變 |
2.5 類型轉(zhuǎn)換
Rust是強靜態(tài)類型語言,幾乎不支持隱式類型轉(zhuǎn)換,所有類型轉(zhuǎn)換必須顯式聲明。
2.5.1 as關(guān)鍵字轉(zhuǎn)換
as關(guān)鍵字是Rust中最常用的類型轉(zhuǎn)換方法,適用于基礎(chǔ)數(shù)據(jù)類型之間的轉(zhuǎn)換。
?? as關(guān)鍵字轉(zhuǎn)換示例:
// 整數(shù)類型之間的轉(zhuǎn)換 let a: i32 = 100; let b: u8 = a as u8; // 100 let c: i8 = 255 as i8; // -1(兩補數(shù)環(huán)繞) // 整數(shù)轉(zhuǎn)浮點數(shù) let d: i32 = 5; let e: f64 = d as f64; // 5.0 // 浮點數(shù)轉(zhuǎn)整數(shù)(截斷) let f: f64 = 3.14; let g: i32 = f as i32; // 3 // 字符轉(zhuǎn)整數(shù) let h: char = 'A'; let i: u32 = h as u32; // 65
?? as關(guān)鍵字轉(zhuǎn)換的限制:
- 不能在非基礎(chǔ)數(shù)據(jù)類型之間轉(zhuǎn)換(如String和&str不能用as轉(zhuǎn)換)
- 浮點數(shù)轉(zhuǎn)整數(shù)會截斷小數(shù)部分,可能導致精度損失
- 大整數(shù)轉(zhuǎn)小整數(shù)會發(fā)生兩補數(shù)環(huán)繞,可能導致未定義行為
2.5.2 From/Into Traits轉(zhuǎn)換
From/Into Traits是Rust中更安全、更通用的類型轉(zhuǎn)換方法,適用于所有實現(xiàn)了這些Traits的類型。
- From Trait:用于將一個類型轉(zhuǎn)換為另一個類型,定義方法是
from() - Into Trait:是From Trait的逆操作,自動實現(xiàn)(只要實現(xiàn)了From Trait,就會自動實現(xiàn)Into Trait),定義方法是
into()
?? From/Into Traits轉(zhuǎn)換示例:
// String和&str之間的轉(zhuǎn)換
let s1: &str = "hello";
let s2: String = String::from(s1); // 使用From Trait
let s3: String = s1.into(); // 使用Into Trait(自動實現(xiàn))
// 整數(shù)類型之間的轉(zhuǎn)換(需要實現(xiàn)From Trait)
use std::convert::TryFrom;
use std::convert::TryInto;
let a: i32 = 100;
let b: Result<u8, std::num::TryFromIntError> = u8::try_from(a); // 安全轉(zhuǎn)換,返回Result
match b {
Ok(x) => println!("a轉(zhuǎn)換為u8:{}", x),
Err(e) => println!("轉(zhuǎn)換失?。簕}", e),
}
let c: Result<u8, std::num::TryFromIntError> = a.try_into(); // 使用TryInto Trait(自動實現(xiàn))
// 自定義類型的轉(zhuǎn)換
struct Person {
name: String,
age: u32,
}
struct PersonInfo {
name: &'static str,
age: u32,
}
impl From<PersonInfo> for Person {
fn from(info: PersonInfo) -> Self {
Person {
name: String::from(info.name),
age: info.age,
}
}
}
let info = PersonInfo { name: "張三", age: 25 };
let person: Person = info.into(); // 使用Into Trait(自動實現(xiàn))
println!("姓名:{},年齡:{}", person.name, person.age); // 姓名:張三,年齡:25
三、真實案例應(yīng)用
3.1 案例1:計算多種幾何圖形的面積
?? 場景分析:需要編寫一個函數(shù),根據(jù)不同的幾何圖形(圓形、矩形、三角形)計算面積,輸入?yún)?shù)類型不同,但返回值都是浮點數(shù)。
?? 代碼示例:
// 定義幾何圖形的枚舉類型
#[derive(Debug)]
enum Shape {
Circle(f64), // 半徑
Rectangle(f64, f64), // 長和寬
Triangle(f64, f64), // 底和高
}
// 計算面積的函數(shù)
impl Shape {
fn area(&self) -> f64 {
match self {
Shape::Circle(radius) => std::f64::consts::PI * radius * radius,
Shape::Rectangle(width, height) => width * height,
Shape::Triangle(base, height) => base * height / 2.0,
}
}
}
fn main() {
// 創(chuàng)建不同的幾何圖形
let circle = Shape::Circle(5.0);
let rectangle = Shape::Rectangle(10.0, 5.0);
let triangle = Shape::Triangle(6.0, 4.0);
// 計算面積
println!("圓形面積:{:.2}", circle.area()); // 78.54
println!("矩形面積:{:.2}", rectangle.area()); // 50.00
println!("三角形面積:{:.2}", triangle.area()); // 12.00
}
3.2 案例2:處理用戶輸入的成績數(shù)據(jù)
?? 場景分析:需要編寫一個程序,讀取用戶輸入的多個學生成績(整數(shù)),計算平均分、最高分、最低分,并輸出成績的分布情況。
?? 代碼示例:
use std::io;
fn main() {
// 存儲成績的數(shù)組(最多50個學生)
let mut scores = [0; 50];
let mut count = 0;
println!("請輸入學生成績(輸入-1結(jié)束):");
loop {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("讀取輸入失敗");
let score: i32 = match input.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("請輸入有效的整數(shù)");
continue;
}
};
if score == -1 {
break;
}
if score < 0 || score > 100 {
println!("成績必須在0-100之間");
continue;
}
if count >= 50 {
println!("最多只能輸入50個成績");
break;
}
scores[count] = score;
count += 1;
}
if count == 0 {
println!("沒有輸入成績");
return;
}
// 計算平均分、最高分、最低分
let sum: i32 = scores[0..count].iter().sum();
let average = sum as f64 / count as f64;
let max_score = scores[0..count].iter().max().unwrap();
let min_score = scores[0..count].iter().min().unwrap();
// 統(tǒng)計成績分布
let mut grade_counts = [0; 5]; // 0-59, 60-69, 70-79, 80-89, 90-100
for &score in scores[0..count].iter() {
match score {
0..=59 => grade_counts[0] += 1,
60..=69 => grade_counts[1] += 1,
70..=79 => grade_counts[2] += 1,
80..=89 => grade_counts[3] += 1,
90..=100 => grade_counts[4] += 1,
_ => (),
}
}
// 輸出結(jié)果
println!("成績統(tǒng)計結(jié)果:");
println!("----------------------");
println!("學生人數(shù):{}", count);
println!("平均分:{:.2}", average);
println!("最高分:{}", max_score);
println!("最低分:{}", min_score);
println!("----------------------");
println!("成績分布:");
println!("0-59分:{}人", grade_counts[0]);
println!("60-69分:{}人", grade_counts[1]);
println!("70-79分:{}人", grade_counts[2]);
println!("80-89分:{}人", grade_counts[3]);
println!("90-100分:{}人", grade_counts[4]);
}
3.3 案例3:解析CSV格式的產(chǎn)品數(shù)據(jù)
?? 場景分析:需要編寫一個程序,讀取CSV格式的產(chǎn)品數(shù)據(jù)(包含產(chǎn)品名稱、價格、庫存),解析并存儲在數(shù)組中,然后根據(jù)價格范圍篩選產(chǎn)品。
?? 代碼示例:
// 產(chǎn)品結(jié)構(gòu)體
#[derive(Debug)]
struct Product {
name: String,
price: f64,
stock: u32,
}
// 解析CSV行的函數(shù)
fn parse_product_csv(line: &str) -> Option<Product> {
let fields: Vec<&str> = line.split(',').collect();
if fields.len() != 3 {
return None;
}
let name = fields[0].trim().to_string();
let price: f64 = match fields[1].trim().parse() {
Ok(num) => num,
Err(_) => return None,
};
let stock: u32 = match fields[2].trim().parse() {
Ok(num) => num,
Err(_) => return None,
};
Some(Product { name, price, stock })
}
fn main() {
// 模擬CSV數(shù)據(jù)
let csv_data = "
蘋果, 5.99, 100
香蕉, 2.49, 200
橙子, 3.99, 150
葡萄, 9.99, 50
西瓜, 12.99, 30
錯誤數(shù)據(jù), abc, 10
";
// 解析CSV數(shù)據(jù)
let mut products = Vec::new();
for line in csv_data.lines() {
let trimmed_line = line.trim();
if trimmed_line.is_empty() {
continue;
}
match parse_product_csv(trimmed_line) {
Some(product) => products.push(product),
None => println!("忽略無效行:{}", trimmed_line),
}
}
// 篩選價格在5-10元之間的產(chǎn)品
let filtered_products: Vec<&Product> = products
.iter()
.filter(|p| p.price >= 5.0 && p.price <= 10.0)
.collect();
// 輸出結(jié)果
println!("價格在5-10元之間的產(chǎn)品:");
println!("----------------------------------");
println!("產(chǎn)品名稱\t價格\t庫存");
println!("----------------------------------");
for product in filtered_products {
println!("{}\t{:.2}\t{}", product.name, product.price, product.stock);
}
}
四、常見問題與解決方案
4.1 整數(shù)溢出導致的崩潰
問題現(xiàn)象:在Debug模式下,整數(shù)溢出會導致程序崩潰(panic!)。
解決方案:
- 使用checked_*系列方法(溢出時返回None)
- 使用saturating_*系列方法(溢出時取最大值/最小值)
- 使用wrapping_*系列方法(強制兩補數(shù)環(huán)繞)
4.2 浮點數(shù)精度導致的邏輯錯誤
問題現(xiàn)象:0.1+0.2的結(jié)果不等于0.3,比較浮點數(shù)相等時返回false。
解決方案:比較兩個浮點數(shù)的差值是否小于一個極小值(epsilon),如1e-9。
4.3 數(shù)組越界訪問導致的崩潰
問題現(xiàn)象:訪問數(shù)組的索引超過其長度時,程序崩潰。
解決方案:
- 在訪問數(shù)組元素前,先檢查索引是否在有效范圍內(nèi)
- 使用get()方法(返回Option類型),避免崩潰
?? get()方法示例:
let a = [1, 2, 3];
if let Some(element) = a.get(3) {
println!("{}", element);
} else {
println!("索引無效");
}
4.4 類型不匹配導致的編譯錯誤
問題現(xiàn)象:函數(shù)接受的參數(shù)類型與傳入的類型不一致,導致編譯錯誤。
解決方案:
- 顯式類型轉(zhuǎn)換(使用as關(guān)鍵字或From/Into Traits)
- 檢查變量的類型注解是否正確
- 使用dbg!()宏打印變量類型(調(diào)試時)
?? dbg!()宏示例:
let x = 10; dbg!(x); // 輸出[src/main.rs:2:5] x = 10 let y = x as u8; dbg!(y); // 輸出[src/main.rs:4:5] y = 10
五、總結(jié)與展望
? 掌握了Rust所有標量類型的定義、內(nèi)存布局、范圍限制與字面量寫法
? 熟練運用了元組、數(shù)組、切片處理復(fù)雜數(shù)據(jù)結(jié)構(gòu),理解了其固定/動態(tài)特性
? 深入理解了變量的聲明、可變性控制、作用域規(guī)則,以及Shadowing(變量隱藏)機制的應(yīng)用場景
? 熟練掌握了Rust嚴格的類型轉(zhuǎn)換方法,包括as關(guān)鍵字和From/Into Traits
? 結(jié)合真實場景編寫了三個實用的代碼案例,解決了常見問題
通過學習這些內(nèi)容,我們將能夠編寫更復(fù)雜、邏輯更清晰的Rust程序。
到此這篇關(guān)于Rust的基礎(chǔ)數(shù)據(jù)類型、變量系統(tǒng)、類型轉(zhuǎn)換以及實戰(zhàn)應(yīng)用的文章就介紹到這了,更多相關(guān)Rust的基礎(chǔ)數(shù)據(jù)類型、變量系統(tǒng)、類型轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust聲明宏在不同K線bar類型中的應(yīng)用小結(jié)
在K線bar中,往往有很多不同分時k線圖,比如1,2,3,5,,,,,60,120,250,300…,,不同分鐘類型,如果不用宏,那么手寫會比較麻煩,下面就試用一下宏來實現(xiàn)不同類型的bar,感興趣的朋友一起看看吧2024-05-05

