【Rust 精進之路之第3篇-變量觀】`let`, `mut` 與 Shadowing:理解 Rust 的變量綁定哲學

系列: Rust 精進之路:構建可靠、高效軟件的底層邏輯
作者: 碼覺客
發布日期: 2025-04-20

引言:為數據命名,Rust 的第一道“安全閥”

在上一篇文章中,我們成功搭建了 Rust 開發環境,并用 Cargo 運行了第一個程序,邁出了堅實的一步。現在,是時候深入了解構成程序的基本單元了。變量,作為在內存中存儲和引用數據的核心機制,在任何編程語言中都至關重要。你可能對 C、Java 或 Python 等語言中的變量聲明和使用非常熟悉。

然而,當你開始接觸 Rust 時,會發現它在處理變量的方式上,從一開始就展現了其獨特且深思熟慮的設計理念。最引人注目的就是對“可變性”的嚴格控制。與許多主流語言默認變量可變不同,Rust 堅定地選擇了默認不可變 (immutable)。這個看似增加了少許“麻煩”的設計,實際上是 Rust 強大的安全保證體系的基石,對于編寫可維護、尤其是在并發環境下可靠的代碼至關重要。

本文將詳細探討 Rust 中變量的聲明方式 (let)、如何審慎地引入可變性 (mut)、定義真正恒定值的常量 (const) 與貫穿程序生命周期的靜態變量 (static),以及一個既實用又可能引起討論的特性——變量“遮蔽 (Shadowing)”。理解這些概念及其背后的原因,不僅是掌握 Rust 語法的基本要求,更是開始領悟 Rust 如何從語言層面就幫助我們構建更健壯、更易于推理的軟件系統的關鍵所在。

一、let:默認的契約——不可變綁定與類型推斷

在 Rust 中,我們使用 let 關鍵字來引入一個新的變量綁定。值得注意的是,Rust 社區傾向于使用“綁定 (binding)”而非“賦值 (assignment)”,以強調 let 語句是將一個名稱與一塊內存數據關聯起來的行為。而這個綁定的核心特性就是:默認不可變

fn main() {// 使用 let 綁定變量 x,并初始化為 5。// Rust 的類型推斷足夠智能,可以推斷出 x 的類型是 i32 (默認整數類型)let x = 5;println!("x 的值是: {}", x); // 輸出: x 的值是: 5// 再次嘗試給 x 賦予新值 - 這違反了不可變性契約// x = 6; // 編譯錯誤: cannot assign twice to immutable variable `x`let message = "Hello"; // message 被推斷為 &str 類型 (字符串切片)// message = "World"; // 同樣編譯錯誤println!("message 的值是: {}", message);// 你也可以顯式標注類型let y: f64 = 3.14; // 明確指定 y 為 64 位浮點數println!("y 的值是: {}", y);
}

編譯器是這條規則的嚴格執行者。任何對不可變綁定的再次賦值嘗試都會在編譯階段被捕獲,程序根本無法通過編譯。

默認不可變性的深層價值:

這個設計決策是 Rust 安全哲學的核心體現,帶來了顯著的好處:

  1. 增強代碼可讀性與可預測性: 當你閱讀一段 Rust 代碼時,看到一個沒有 mutlet 綁定,你可以立即確信這個變量的值在其作用域內不會發生改變。這極大地降低了理解和推理代碼狀態的認知負擔,尤其是在處理復雜邏輯或遺留代碼時。想象一下調試一個長函數,如果大部分變量都是不可變的,追蹤數據流會容易得多。
  2. 編譯時安全保證: 許多難以察覺的運行時 Bug 源于狀態的意外變更。Rust 將這種檢查提前到編譯時,強制開發者明確意圖。如果代碼能編譯通過(在 safe Rust 范疇內),就意味著你已經消除了大量因意外修改變量而導致的潛在錯誤。
  3. 為“無畏并發”奠定基礎: 不可變數據是并發編程的福音。多個線程可以同時讀取不可變數據而無需任何同步機制(如鎖),因為不存在數據競爭的風險。Rust 的所有權和借用系統(我們將在后面深入學習)與默認不可變性協同工作,構成了其強大的并發安全模型的基礎。

同時,Rust 強大的類型推斷 (Type Inference) 機制使得在大多數情況下,你無需顯式標注變量類型,編譯器能根據初始值和上下文推斷出來,保持了代碼的簡潔性。

二、mut:顯式聲明——審慎地引入可變性

當然,程序需要處理變化的狀態。Rust 并沒有禁止可變性,而是要求你顯式地、有意識地選擇它。通過在 let 后面添加 mut 關鍵字,你可以聲明一個變量綁定是可變的 (mutable)

fn main() {// 使用 let mut 聲明一個可變變量 counterlet mut counter: u32 = 0; // 顯式標注類型為 u32println!("計數器初始值: {}", counter); // 輸出: 0counter = counter + 1; // 合法操作,因為 counter 是可變的println!("計數器加 1 后: {}", counter); // 輸出: 1let mut name = String::from("Alice"); // 創建一個可變的 Stringprintln!("初始名字: {}", name);name.push_str(" Smith"); // 調用 String 的方法修改其內容println!("修改后名字: {}", name);
}

重點理解: mut 是綁定的一部分,它修飾的是變量名(即這個“標簽”允許被貼到不同的值上,或者允許修改其指向的值的內容,取決于類型),而不是類型本身。let mut x: i32 是正確的,而 let x: mut i32 是錯誤的語法。

可變性的權衡與慣用法:

引入 mut 意味著賦予了代碼改變狀態的能力,這帶來了靈活性,但也引入了復雜性。你需要更仔細地追蹤變量值的變化,尤其是在較長的函數或跨模塊交互中。

Rust 的編程風格強烈建議優先選擇不可變性。只在邏輯確實需要(例如循環計數、累積結果、修改集合內容如 VecString)時才使用 mut。這樣做的好處是:

  • 意圖清晰: mut 關鍵字像一個警示牌,明確標示出代碼中可能發生狀態變化的地方。
  • 局部化影響: 盡量將可變性限制在最小的必要范圍內(例如,一個函數內部),避免不必要的可變狀態擴散。
  • 擁抱函數式風格: 鼓勵通過創建新值(例如使用 map, filter 等迭代器方法,或者使用 Shadowing)來處理數據轉換,而不是原地修改。

三、const:恒定之值——編譯時確定的不變量

Rust 提供了常量 (Constants),使用 const 關鍵字聲明。它們代表了程序中真正意義上的、固定不變的值。與不可變 let 綁定相比,const 有著更嚴格的定義和不同的特性:

  1. 絕對不可變: const 不能使用 mut。它們的值在編譯后就固定下來。
  2. 編譯時求值: const 的值必須是一個常量表達式 (Constant Expression),即其值必須在編譯期間就能完全計算出來。不能依賴任何運行時才能確定的信息(如函數調用結果、環境變量等)。
  3. 類型必須顯式標注: 聲明 const 時,類型注解是強制性的。
  4. 全局可用性: const 可以在任何作用域聲明,包括模塊的根作用域(全局作用域)。
  5. 無固定內存地址(通常): 編譯器通常會將 const 的值直接“內聯”到使用它的地方,類似于 C/C++ 中的 #define 但帶有類型檢查。這意味著常量本身在運行時可能不作為一個獨立的內存對象存在。
  6. 命名約定: 遵循全大寫字母和下劃線分隔的約定(如 SECONDS_IN_HOUR)。
// 定義一些數學和物理常量
const PI: f64 = 3.141592653589793;
const SPEED_OF_LIGHT_METERS_PER_SECOND: u32 = 299_792_458;// 定義配置相關的常量
const MAX_CONNECTIONS: usize = 100;
const DEFAULT_TIMEOUT_MS: u64 = 5000;// 也可以用于簡單的計算,只要能在編譯時完成
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;fn main() {println!("圓周率約等于: {}", PI);println!("默認超時時間: {}ms", DEFAULT_TIMEOUT_MS);println!("三小時等于 {} 秒", THREE_HOURS_IN_SECONDS);// const 不能是運行時才能確定的值// use std::time::Instant;// const START_TIME: Instant = Instant::now(); // 編譯錯誤!now() 是運行時函數
}// `const fn` 允許在編譯時執行更復雜的計算來初始化常量
const fn compute_initial_value(x: u32) -> u32 {x * x + 1 // 這個計算可以在編譯時完成
}
const INITIAL_VALUE: u32 = compute_initial_value(5); // 合法

const 的價值:

  • 語義清晰: 明確表達一個值是程序設計中的固定參數或不變真理。
  • 性能優化: 編譯時求值和內聯可以提高運行時性能。
  • 代碼維護: 將魔法數字或配置值定義為常量,易于查找和修改。

四、static:貫穿全程——具有固定地址的靜態變量

Rust 的靜態變量 (Static Variables) 使用 static 關鍵字聲明,它們代表在程序的整個生命周期內都存在的值。其關鍵特性:

  1. 'static 生命周期: 這是 Rust 中最長的生命周期,表示變量與程序本身“同壽”。
  2. 固定內存地址:const 不同,static 變量在內存中有確定的、固定的存儲位置。程序中所有對該 static 變量的引用都指向這個唯一的地址。這使得獲取靜態變量的引用(指針)成為可能。
  3. 可變性 (static mut) 與 unsafe
    • static 變量可以是可變的,使用 static mut 聲明。
    • 然而,任何對 static mut 變量的訪問(讀取或寫入)都必須在 unsafe { ... } 代碼塊中進行。這是 Rust 的一個核心安全規則。
    • 原因: 全局可變狀態是數據競爭的主要溫床。編譯器無法在編譯時靜態地保證對 static mut 的并發訪問是安全的(因為它繞過了借用檢查器的保護)。unsafe 塊意味著開發者向編譯器保證:“我知道這里的風險,并且我已經采取了必要的外部措施(如鎖、原子操作或其他同步機制)來確保線程安全。” 如果沒有這些措施,就可能導致未定義行為。
  4. 類型必須顯式標注。
  5. 命名約定:const 相同,全大寫。
use std::sync::atomic::{AtomicUsize, Ordering};// 不可變的靜態變量,通常用于全局配置或只讀數據
static APPLICATION_VERSION: &str = "1.0.2";// 使用原子類型實現線程安全的全局計數器 (推薦方式)
static SAFE_COUNTER: AtomicUsize = AtomicUsize::new(0);// 可變的靜態變量 (極不推薦,僅作演示)
static mut UNSAFE_GLOBAL_DATA: Vec<i32> = Vec::new(); // 全局可變 Vec,非常危險!fn increment_safe_counter() {// 原子操作是線程安全的,不需要 unsafeSAFE_COUNTER.fetch_add(1, Ordering::SeqCst);
}fn add_to_unsafe_data(value: i32) {// 必須使用 unsafe,并且需要外部同步來保證安全,這里省略了同步,非常危險!unsafe {UNSAFE_GLOBAL_DATA.push(value);}
}fn main() {println!("應用版本: {}", APPLICATION_VERSION);increment_safe_counter();println!("安全計數器: {}", SAFE_COUNTER.load(Ordering::SeqCst)); // 輸出: 1// add_to_unsafe_data(42); // 即使在單線程,也需要 unsafe// unsafe {//     println!("不安全數據: {:?}", UNSAFE_GLOBAL_DATA);// }// 何時可能需要 static?// 1. 需要一個全局的、有固定地址的實例 (例如 FFI 中傳遞給 C 庫的回調上下文)// 2. 需要一個在編譯時初始化,但在整個程序生命周期內保持不變的復雜對象 (可以使用 lazy_static 或 once_cell 庫安全地初始化)
}

static vs const 深入對比:

特性conststatic
求值時間編譯時編譯時初始化 (值必須是常量表達式)
內存地址通常無固定地址 (可能內聯)有固定內存地址
生命周期無 (值直接使用)'static (整個程序運行期間)
可變性永不可變mut (但訪問需 unsafe)
存儲位置可能在代碼段或優化掉通常在靜態數據區 (.data 或 .bss)
主要用途定義不變常量、配置定義全局狀態、固定地址數據 (謹慎使用可變)

核心建議: 優先使用 const 定義不變值。需要全局固定地址時才考慮 static極力避免使用 static mut,應選擇 Mutex, RwLock, Atomic 類型等線程安全的并發原語來管理共享可變狀態,通常結合 lazy_staticonce_cell 來進行安全的初始化。

五、Shadowing (遮蔽):同名新綁定,靈活的值演化

Rust 提供了一個名為遮蔽 (Shadowing) 的特性,它允許你在同一作用域內,使用 let 關鍵字再次聲明一個與先前變量同名的變量。這個新變量會“遮蔽”掉舊變量,使得在當前及內部作用域中,該名稱指向的是新變量。

理解遮蔽的關鍵:

  • 創建全新變量: 遮蔽不是修改(mutate)舊變量的值或類型。它是創建了一個完全獨立的新變量,只不過復用了之前的名稱。舊變量依然存在,只是在當前作用域內暫時無法通過該名稱訪問(一旦離開新變量的作用域,舊變量可能重新變得可見)。
  • 允許類型變更: 正因為是創建新變量,所以遮蔽后的變量可以擁有與被遮蔽變量不同的類型。這是它與 mut 修改的核心區別(mut 不能改變變量類型)。
  • 作用域規則: 遮蔽遵循詞法作用域。內部作用域的遮蔽不會影響外部作用域。
fn main() {let x = 5;println!("(1) x = {}", x); // 輸出: 5// 遮蔽 x,創建一個新的 xlet x = x + 10; // 新 x 的值是舊 x (5) + 10 = 15println!("(2) x = {}", x); // 輸出: 15{// 在新的作用域內再次遮蔽 xlet x = "hello"; // 這個 x 是 &str 類型,遮蔽了外層的數字 xprintln!("(3) 內部 x = {}", x); // 輸出: hello} // 內部作用域結束,字符串 x 消失// 回到外部作用域,數字 15 的 x 重新可見println!("(4) 回到外部 x = {}", x); // 輸出: 15// 示例:逐步處理用戶輸入let input_str = "  42  "; // 原始輸入,類型 &strprintln!("原始輸入: '{}'", input_str);let input_str = input_str.trim(); // 遮蔽,去除首尾空格,類型仍為 &strprintln!("去除空格后: '{}'", input_str);let number = input_str.parse::<i32>(); // 嘗試解析,結果是 Result<i32, _>// 這里不使用遮蔽,因為需要處理 Resultmatch number {Ok(num) => {// 可以在這里遮蔽 number (如果需要繼續使用這個名字)let number = num * 2; // 遮蔽,新 number 是 i32 類型println!("解析成功并乘以 2: {}", number); // 輸出: 84}Err(_) => {println!("解析失敗");}}// 也可以用 let number = number.unwrap(); 等方式遮蔽,但需確保 Ok
}

遮蔽的實用場景與考量:

  • 值的轉換與精煉: 非常適合在一系列步驟中處理數據,每一步的結果用相同的名字表示演化后的狀態,例如類型轉換、單位換算、數據清洗(如 trim 示例)。這避免了創造一堆類似 value_step1, value_step2 的臨時變量名。
  • 保持概念統一: 當一個變量的邏輯含義保持不變,但其具體表示或類型發生變化時,使用遮蔽可以維持代碼的概念連貫性。
  • 有限作用域內的臨時覆蓋: 在一個代碼塊內部臨時使用一個同名變量,而不影響外部同名變量。

注意事項: 雖然遮蔽很方便,但在冗長或復雜的函數中過度使用可能導致混淆——讀者需要仔細追蹤當前哪個“版本”的變量在起作用。因此,建議在邏輯清晰、作用域相對較小的范圍內適度使用遮蔽,始終以代碼的可讀性可維護性為首要標準。

六、設計哲學:安全、顯式與清晰——Rust 對狀態管理的深思

通過對 let, mut, const, static 和 Shadowing 的探討,我們可以更清晰地看到 Rust 在狀態管理上的核心設計原則:

  • 安全是默認選項: 默認不可變性將意外修改狀態的風險降至最低,構成了 Rust 內存安全和并發安全的基礎。
  • 意圖必須顯式: 無論是引入可變性 (mut) 還是處理潛在不安全的操作 (unsafe for static mut),都需要開發者明確表達意圖,不能模棱兩可。
  • 區分不同性質的不變性: conststatic 為編譯時常量和全局靜態值提供了不同的語義和實現,讓概念更清晰。
  • 提供受控的靈活性: Shadowing 在不破壞不可變性原則的前提下,提供了一種實用的值演化和名稱重用機制。

這些設計并非為了限制開發者,而是為了賦能開發者。通過在編譯時強制執行更嚴格的規則,Rust 幫助我們構建出更可靠、更易于推理、更適應并發環境的軟件系統。它將許多傳統上需要在運行時擔心或通過測試覆蓋的問題,提前暴露在開發階段,大大降低了后期維護成本和風險。

七、常見問題回顧與深化 (FAQ)

  • Q1: 默認不可變會不會讓代碼更啰嗦?
    • A: 初期可能會感覺需要多打 mut,但長期來看,它帶來的代碼清晰度和安全性收益遠超這點“麻煩”。Rust 的函數式編程特性(如迭代器、mapfilter)和 Shadowing 也提供了很多無需 mut 就能優雅處理數據轉換的方法。
  • Q2: static mut 真的很糟糕嗎?它存在的意義是什么?
    • A: 是的,它非常容易誤用并導致嚴重問題(數據競爭、未定義行為)。其主要存在意義是為了與 C 語言庫進行 FFI(外部函數接口)交互,因為 C 語言中全局可變變量很常見。在純 Rust 代碼中,幾乎總有更安全的替代方案(Mutex, Atomic 等)。使用 static mut 意味著你放棄了 Rust 編譯器的安全保障,必須自己承擔全部責任。
  • Q3: Shadowing 和其他語言的變量重用(比如 Python)有何不同?
    • A: Python 等動態類型語言中,同一個變量名可以隨時指向不同類型的值,這是語言動態性的體現。Rust 的 Shadowing 是在靜態類型系統下實現的:每次 let 都是一次新的類型檢查和綁定,舊變量(及其類型)在作用域內被隱藏。它更像是在同一個“標簽”下創建了多個不同類型、生命周期可能重疊但定義獨立的變量。
  • Q4: 在函數參數中,是默認不可變嗎?如何接受可變參數?
    • A: 是的,函數參數默認也是不可變綁定。如果函數需要修改傳入的參數(通常是通過可變引用),參數類型需要明確標記為可變引用,例如 fn modify(value: &mut i32)。我們將在后續關于引用和借用的章節詳細探討。

總結:變量綁定——構筑 Rust 可靠性的第一塊磚

本文深入探討了 Rust 中變量聲明與使用的各種機制:let 的默認不可變性、mut 的顯式可變性、const 的編譯時常量、static 的全局靜態變量(以及 static mut 的風險),還有靈活的 Shadowing 特性。

我們不僅學習了它們的語法和行為,更重要的是理解了這些設計背后貫穿著 Rust 對安全性、顯式性和清晰性的執著追求。Rust 通過在語言層面就對狀態變化進行嚴格管理,幫助開發者從源頭避免錯誤,構建出更加健壯和可靠的軟件。

掌握好 Rust 如何定義和管理變量,是理解其所有權、借用等核心概念的基礎。現在我們熟悉了為數據命名的規則,下一站,我們將開始探索 Rust 所提供的豐富的數據類型本身。

下一篇預告:【數據基石·上】標量類型——深入了解 Rust 中的整數、浮點數、布爾和字符類型。這些基礎類型在 Rust 中有哪些細節和特性值得我們關注?敬請期待!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79793.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79793.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79793.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

stm32(IO口的最高速度)

如果我們寫入速度 快到一種程度 肯定就不能完全按理想的來了 當我們寫01快起來 中間的保持時間就會越來越少 就逐漸往下面變化 所以其實 我們如果改變上升時間 和 下降時間 還是能將最后的波形 變成為正常的波形的。 不用追求高速 &#xff0c;滿足要求下 選低速的即可。 因…

String +memset字符串類題型【C++】

tips&#xff1a; 1、尋找最大公共子串時&#xff0c;如果字符串可以旋轉但是不能反轉&#xff0c;考慮在每個字符串后重復一次自身&#xff0c;如 "abcd" 變為 "abcdabcd"&#xff0c;這樣在用dp就可以了。 如何變環拆環為鏈&#xff1a; cin>>n&…

基于論文的大模型應用:基于SmartETL的arXiv論文數據接入與預處理(三)

上一篇 介紹了數據接入處理的整體方案設計。本篇介紹基于SmartETL框架的流程實現。 5. 流程開發 5.1.簡單采集流程 從指定時間&#xff08;yy年 mm月&#xff09;開始&#xff0c;持續采集arXiv論文。基于月份和順序號&#xff0c;構造論文ID&#xff0c;進而下載論文PDF文件…

[Swift]Xcode模擬器無法請求http接口問題

1.以前偷懶一直是這樣設置 <key>NSAppTransportSecurity</key> <dict><key>NSAllowsArbitraryLoads</key><true/><key>NSAllowsArbitraryLoadsInWebContent</key><true/> </dict> 現在我在Xcode16.3上&#xff…

Python基礎總結(八)之循環語句

文章目錄 一、for循環1.1 for循環格式1.2 for ...else1.3 for...break1.4 for...continue 二、while循環2.1 while循環格式2.2 while...break2.3 while...continue2.4 while ...else 循環語句就如其名&#xff0c;就是重復的執行一段代碼&#xff0c;直到滿足退出條件時&#x…

vuex實現同一頁面radio-group點擊不同按鈕顯示不同表單

本文實現的是點擊單一規格和多規格兩個按鈕會在頁面顯示不同的表單 方法一 <!-- 單規格和多規格的切換 --> <el-form label-width"80px" class"text-align-left"><el-form-item label"商品規格"><!-- 監聽skus_type的改…

AI編寫的“黑科技風格、自動刷新”的看板頁面

以下的 index.html 、 script.js 和 styles.css 文件&#xff0c;實現一個具有黑科技風格、自動刷新的能源管理系統實時監控看板。 html頁面 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name&q…

Vim使用完全指南:從基礎到高效編輯

Vim使用完全指南&#xff1a;從基礎到高效編輯 一、Vim簡介與基本概念 Vim&#xff08;Vi IMproved&#xff09;是從vi發展出來的一個功能強大的文本編輯器&#xff0c;以其高效性和靈活性著稱&#xff0c;特別適合程序開發和系統管理任務。與常規文本編輯器不同&#xff0c;…

時序約束高級進階使用詳解三:Create_Clock

目錄 一、前言 二、設計示例 2.1 設計代碼 2.2 schematic 2.3 no overwriteing 2.4 約束到非時鐘引腳 三、Create_clock應用 3.1 時鐘輸入端口 3.2 7系列高速收發器輸出管腳 3.3 部分原語的輸出管腳 3.4 主時鐘路徑上創建主時鐘 3.5 虛擬時鐘 3.6 差分時鐘的約束 …

箱線圖(盒須圖)QCPStatiBox

一、QCPStatisticalBox 概述 QCPStatisticalBox 是 QCustomPlot 中用于繪制箱線圖(盒須圖)的類&#xff0c;可以顯示數據的五個關鍵統計量&#xff1a;最小值、第一四分位數(Q1)、中位數、第三四分位數(Q3)和最大值&#xff0c;以及可能的異常值。 二、主要屬性 屬性類型描述…

人形機器人馬拉松:北京何以孕育“領跑者”?

“機器人每跑一小步&#xff0c;都是人類科技的一大步”&#xff0c;這句對阿姆斯特朗登月名言的仿寫&#xff0c;恰如其分地詮釋了全球首場人形機器人半程馬拉松賽事的里程碑意義。 2025年4月19日&#xff0c;北京亦莊半程馬拉松暨人形機器人半程馬拉松圓滿結束。在總長21.09…

基于Python的推薦算法的電影推薦系統的設計

標題:基于Python的推薦算法的電影推薦系統的設計與實現 內容:1.摘要 本文圍繞基于Python的推薦算法的電影推薦系統展開研究。背景在于隨著電影數量的急劇增加&#xff0c;用戶在海量電影中找到符合自身喜好的影片變得困難。目的是設計并實現一個高效準確的電影推薦系統&#x…

【深度學習】詳解矩陣乘法、點積,內積,外積、哈達瑪積極其應用|tensor系列02

博主簡介&#xff1a;努力學習的22級計算機科學與技術本科生一枚&#x1f338;博主主頁&#xff1a; Yaoyao2024往期回顧&#xff1a;【深度學習】你真的理解張量了嗎&#xff1f;|標量、向量、矩陣、張量的秩|01每日一言&#x1f33c;: “腦袋想不明白的&#xff0c;就用腳想”…

面試常用基礎算法

目錄 快速排序歸并排序堆排序 n n n皇后問題最大和子數組爬樓梯中心擴展法求最長回文子序列分割回文串動態規劃求最長回文子序列最長回文子串單調棧雙指針算法修改 分割回文串滑動窗口棧 快速排序 #include <iostream> #include <algorithm>using namespace std;…

相對路徑和絕對路徑解析

在 Linux/Unix 和文件系統中&#xff0c;絕對路徑和相對路徑是描述文件或目錄位置的兩種方式&#xff0c;它們的核心區別在于路徑的起點和使用場景。以下是詳細對比&#xff1a; 目錄 1. 定義與起點 2. 符號與語法 3. 使用場景 4. 實際示例 示例 1&#xff1a;定位文件 示…

【算法數據結構】leetcode37 解數獨

37. 解數獨 - 力扣&#xff08;LeetCode&#xff09; 題目描述&#xff1a; 題目要求每一行 &#xff0c;每一列&#xff0c;每個3*3 的子框只能出現一次。每個格子的數字范圍1-9. 需要遍歷每個空格填入可能的數字&#xff0c;并驗證符合規則。如果符合就填入&#xff0c;不符…

Vector的學習

vector簡介 vector的相關文檔對于想深入了解的同學可以參考這個文檔進行學習。 vector是表示可變大小數組的序列容器。 就像數組一樣&#xff0c;vector也采用的連續存儲空間來存儲元素。也就是意味著可以采用下標對vector的元素進行訪問&#xff0c;和數組一樣高效。但是又不…

Vue常用指令入門

1. v-for 作用&#xff1a;用于遍歷對象或數組 注意&#xff1a;需要提供key屬性&#xff0c;可以提高性能和避免渲染錯誤&#xff0c;值通常為index或item.id <li v-for"(item, index) in items" :key"index">{{ item }} </li>2. v-if,v-el…

在機器視覺檢測中為何選擇線陣工業相機?

線陣工業相機&#xff0c;顧名思義是成像傳感器呈“線”狀的。雖然也是二維圖像&#xff0c;但極寬&#xff0c;幾千個像素的寬度&#xff0c;而高度卻只有幾個像素的而已。一般在兩種情況下使用這種相機&#xff1a; 1. 被測視野為細長的帶狀&#xff0c;多用于滾筒上檢測的問…

線性DP:最長上升子序列(子序列可不連續,子數組必須連續)

目錄 Q1&#xff1a;簡單遍歷 Q2&#xff1a;變式&#xff08;加大數據量&#xff09; Q1&#xff1a;簡單遍歷 Dp問題 狀態表示 f(i,j) 集合所有以第i個數結尾的上升子序列集合-f(i,j)的值存的是什么序列長度最大值max- 狀態計算 &#xff08;其實質是集合的劃分&#xff09;…