Rust 所有權特性詳解

Rust 所有權特性詳解

Rust 的所有權系統是其內存安全的核心機制之一。通過所有權規則,Rust 在編譯時避免了常見的內存錯誤(如空指針、數據競爭等)。本文將從堆內存與棧內存、所有權規則、變量作用域、String 類型、內存分配、所有權移動、Clone、棧內存的 Copy、所有權與函數、返回值與作用域等角度詳細介紹 Rust 的所有權特性,并通過綜合示例展示這些知識點的實際應用。


1. 什么是堆內存和棧內存

  • 棧內存

    • 后進先出(LIFO)的數據結構。
    • 分配和釋放速度快。
    • 用于存儲固定大小的數據(如基本類型,Rust的基本類型有哪些,他們存在堆內存還是棧內存?)。
  • 堆內存

    • 動態分配的內存區域。
    • 分配和釋放速度較慢。
    • 用于存儲大小可變或生命周期不確定的數據(如 StringVec)。

示例:棧內存與堆內存

fn main() {let x = 5; // x 存儲在棧上let s = String::from("你好"); // s 的數據存儲在堆上,指針存儲在棧上println!("x: {}, s: {}", x, s);
}

輸出

x: 5, s: 你好

分析

  • x 是基本類型,存儲在棧上。
  • sString 類型,數據存儲在堆上,指針和長度等信息存儲在棧上。

2. Rust 所有權的規則

Rust 的所有權規則如下:

  1. 每個值都有一個所有者。
  2. 同一時間只能有一個所有者。
  3. 當所有者離開作用域時,值會被自動釋放。

示例:所有權規則

fn main() {let s1 = String::from("你好");let s2 = s1; // s1 的所有權轉移到 s2// println!("{}", s1); // 錯誤:s1 不再擁有數據println!("s2: {}", s2);
}

輸出

s2: 你好

分析

  • s1 的所有權在賦值給 s2 后轉移,s1 不再有效。

3. 變量的作用域

變量的作用域是從聲明開始到當前塊結束。

示例:變量作用域

fn main() {let s = String::from("你好"); // s 進入作用域{let inner_s = String::from("內部"); // inner_s 進入作用域println!("內部作用域: {}", inner_s);} // inner_s 離開作用域,內存被釋放println!("外部作用域: {}", s);
} // s 離開作用域,內存被釋放

輸出

內部作用域: 內部
外部作用域: 你好

分析

  • inner_s 的作用域僅限于內部塊。
  • s 的作用域是整個 main 函數。

4. String 類型

String 是 Rust 中動態分配的字符串類型,存儲在堆上。

示例:String 類型

fn main() {let mut s = String::from("你好");s.push_str(", Rust!"); // 修改字符串println!("{}", s);
}

輸出

你好, Rust!

分析

  • String 類型允許動態修改內容。

5. 內存分配

Rust 通過所有權系統自動管理堆內存的分配和釋放。

示例:內存分配

fn main() {let s = String::from("你好"); // 分配堆內存println!("{}", s);
} // s 離開作用域,內存被釋放

輸出

你好

分析

  • String::from 分配堆內存。
  • s 離開作用域時,內存被自動釋放。

6. 所有權移動時變量和數據的狀態變化

當所有權從一個變量移動到另一個變量時,原始變量將失效。

示例:所有權移動

fn main() {let s1 = String::from("hello");let s2 = s1; // s1 的所有權移動到 s2// println!("{}", s1); // 錯誤:s1 不再有效println!("s2: {}", s2);
}

輸出

s2: hello

分析
在這里插入圖片描述
-s1的指針存在棧內存,棧內存的value指向堆內存的第一個索引位置。
在這里插入圖片描述

  • 當執行s2=s1的時候,僅僅復制了棧內存上的數據,堆內存的內容不不變。如果堆內存上的數據非常大,復制的操作成本會無限增加!
  • Double Free問題:當前s1、s2都指向同一份數據,當這兩個變量離開作用域時,他們會同時釋放同一塊內存,這就會引起Double Free安全問題。為了確保內存安全,當執行到語句let s2=s1時,Rust讓s1失效,也稱之為將所有權轉移給了s2
  • s1 的所有權轉移給 s2 后,s1 失效(如下圖所示)。
    在這里插入圖片描述

7. 作用域和內存分配

變量的作用域決定了其內存的生命周期。

示例:作用域和內存分配

fn main() {let s = String::from("你好"); // s 進入作用域,分配內存println!("{}", s);
} // s 離開作用域,內存被釋放

輸出

你好

分析

  • s 的作用域結束后,內存被自動釋放。

8. Clone

Clone 允許顯式復制堆上的數據。

示例:Clone

fn main() {let s1 = String::from("你好");let s2 = s1.clone(); // 顯式復制數據println!("s1: {}, s2: {}", s1, s2);
}

輸出

s1: 你好, s2: 你好

分析

  • clone 會復制堆上的數據,s1s2 都有效。

9. 棧內存的 Copy

基本類型實現了 Copy trait,賦值時會復制值而不是移動所有權。

示例:棧內存的 Copy

fn main() {let x = 5;let y = x; // x 的值被復制println!("x: {}, y: {}", x, y);
}

輸出

x: 5, y: 5

分析

  • xy 都有效,因為 i32 實現了 Copy

那么,哪些類型實現了 Copy 特質呢?你可以查看特定類型的文檔來確認,但一般來說,任何由簡單標量值組成的類型都可以實現 Copy,而任何需要分配內存或是某種形式的資源的類型則不能實現 Copy。以下是一些實現了 Copy 的類型:

  • 所有的整數類型,例如 u32
  • 布爾類型 bool,其值為 truefalse
  • 所有的浮點數類型,例如 f64
  • 字符類型 char
  • 元組,如果它們只包含同樣實現了 Copy 的類型。例如,(i32, i32) 實現了 Copy,但 (i32, String) 則沒有。

10. 所有權和函數

將值傳遞給函數會轉移所有權。

示例:所有權和函數

fn take_ownership(s: String) {println!("函數內部: {}", s);
} // s 離開作用域,內存被釋放fn main() {let s = String::from("你好");take_ownership(s); // s 的所有權轉移到函數// println!("{}", s); // 錯誤:s 不再有效
}

輸出

函數內部: 你好

分析

  • s 的所有權在傳遞給函數后轉移。

11. 返回值和作用域

函數可以通過返回值轉移所有權。

示例:返回值和作用域

fn give_ownership() -> String {let s = String::from("你好");s // 返回 s,所有權轉移給調用者
}fn main() {let s = give_ownership(); // s 獲得所有權println!("{}", s);
}

輸出

你好

分析

  • give_ownership 返回 s,所有權轉移給 main 函數中的 s

綜合示例

以下是一個綜合示例,展示了所有權、作用域、CloneCopy、函數與返回值的用法:

fn main() {// 棧內存的 Copylet x = 5;let y = x; // x 的值被復制println!("x: {}, y: {}", x, y);// 堆內存的所有權let s1 = String::from("你好");let s2 = s1.clone(); // 顯式復制數據println!("s1: {}, s2: {}", s1, s2);// 所有權和函數let s3 = String::from("世界");take_ownership(s3); // s3 的所有權轉移到函數// println!("{}", s3); // 錯誤:s3 不再有效// 返回值和作用域let s4 = give_ownership(); // s4 獲得所有權println!("s4: {}", s4);
}fn take_ownership(s: String) {println!("函數內部: {}", s);
} // s 離開作用域,內存被釋放fn give_ownership() -> String {let s = String::from("你好,世界");s // 返回 s,所有權轉移給調用者
}

輸出

x: 5, y: 5
s1: 你好, s2: 你好
函數內部: 世界
s4: 你好,世界

分析

  1. xy 是基本類型,賦值時復制值。
  2. s1s2String 類型,使用 clone 顯式復制數據。
  3. s3 的所有權在傳遞給函數后轉移。
  4. s4 通過函數返回值獲得所有權。

總結

Rust 的所有權系統通過以下特性確保內存安全:

  1. 堆內存與棧內存:區分數據的存儲位置。
  2. 所有權規則:確保每個值只有一個所有者。
  3. 作用域:決定變量的生命周期。
  4. String 類型:動態分配的字符串。
  5. 內存分配:自動管理堆內存。
  6. 所有權移動:轉移所有權時原始變量失效。
  7. Clone:顯式復制堆數據。
  8. 棧內存的 Copy:基本類型賦值時復制值。
  9. 所有權與函數:傳遞值會轉移所有權。
  10. 返回值與作用域:通過返回值轉移所有權。

通過合理使用這些特性,可以編寫出高效且安全的 Rust 代碼。

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

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

相關文章

MVS pythonSamples 運行環境配置

1.首先計算機:操作系統Win10_X64 22H2; 2.MVS V4.4.0 3.python3.8.8_64; 安裝時勾選添加path; 最后安裝依賴包:(所有必須安裝) 圖像處理: mvtec-halcon23050(可選) p…

java練習(5)

ps:題目來自力扣 給你兩個 非空 的鏈表,表示兩個非負的整數。它們每位數字都是按照 逆序 的方式存儲的,并且每個節點只能存儲 一位 數字。 請你將兩個數相加,并以相同形式返回一個表示和的鏈表。 你可以假設除了數字 0 之外,這…

[EAI-023] FAST,機器人動作專用的Tokenizer,提高VLA模型的能力和訓練效率

Paper Card 論文標題:FAST: Efficient Action Tokenization for Vision-Language-Action Models 論文作者:Karl Pertsch, Kyle Stachowicz, Brian Ichter, Danny Driess, Suraj Nair, Quan Vuong, Oier Mees, Chelsea Finn, Sergey Levine 論文鏈接&…

PHP Composer:高效依賴管理工具詳解

PHP Composer:高效依賴管理工具詳解 引言 在PHP開發領域,依賴管理是項目構建過程中的重要環節。Composer的出現,極大地簡化了PHP項目的依賴管理,使得開發者可以更加高效地構建和維護PHP應用程序。本文將深入探討PHP Composer的使用方法、功能特點以及它在項目開發中的應用…

CodeGPT使用本地部署DeepSeek Coder

目前NV和github都托管了DeepSeek,生成Key后可以很方便的用CodeGPT接入。CodeGPT有三種方式使用AI,分別時Agents,Local LLMs(本地部署AI大模型),LLMs Cloud Model(云端大模型,從你自己…

黑盒/白盒運維監控

運維監控分為黑盒和白盒 黑盒:不深入代碼,在系統角度看TPS,延遲等指標 白盒:深入代碼分析,通過日志捕捉,以及主動上報告警等來進行監控 黑盒監控: 1. 頁面功能:域名是否可訪問&…

Rust 中的注釋使用指南

Rust 中的注釋使用指南 注釋是代碼中不可或缺的一部分,它幫助開發者理解代碼的邏輯和意圖。Rust 提供了多種注釋方式,包括行注釋、塊注釋和文檔注釋。本文將詳細介紹這些注釋的使用方法,并通過一個示例展示如何在實際代碼中應用注釋。 1. 行…

可被electron等調用的Qt截圖-錄屏工具【源碼開放】

1. 工具功能簡介: (1)、QT5.15.2截圖工具(exe)可單獨使用或嵌入IM(嵌入方法參照:https://gitee.com/lykiao/yfscreenshot_release) (2)、支持通過Windows消息通知截圖成功或取消 (3)、支持圓形、矩形、線條…

ubuntu系統入門流程

學習流程 安裝雙系統(win11ubuntu隨便啥版本,博客里面下的時候自己選) ->了解一下常見的操作系統類-> 了解ubuntu系統常見文件目錄是做什么的- > 了解一些ubuntu常用指令 ->安裝常用的軟件(qq、vx,學習的…

STM32單片機學習記錄(2.2)

一、STM32 13.1 - PWR簡介 1. PWR(Power Control)電源控制 (1)PWR負責管理STM32內部的電源供電部分,可以實現可編程電壓監測器和低功耗模式的功能; (2)可編程電壓監測器(…

韓語字符分析

查看unicode文檔,發現韓語字符有11172個,這是192128,其實就是19212868個符號的排列組合。分析如下: 第一部分: ??????????????????? 去掉右邊的那個“卜”,共19個符號。 第二部分&#…

基于SpringBoot的智慧康老療養院管理系統的設計與實現(源碼+SQL腳本+LW+部署講解等)

專注于大學生項目實戰開發,講解,畢業答疑輔導,歡迎高校老師/同行前輩交流合作?。 技術范圍:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容:…

goframe 博客分類文章模型文檔 主要解決關聯

goframe 博客文章模型文檔 模型結構 (BlogArticleInfoRes) BlogArticleInfoRes 結構體代表系統中的一篇博客文章,包含完整的元數據和內容管理功能。 type BlogArticleInfoRes struct {Id uint orm:"id,primary" json:"id" …

MQTT知識

MQTT協議 MQTT 是一種基于發布/訂閱模式的輕量級消息傳輸協議,專門針對低帶寬和不穩定網絡環境的物聯網應用而設計,可以用極少的代碼為聯網設備提供實時可靠的消息服務。MQTT 協議廣泛應用于物聯網、移動互聯網、智能硬件、車聯網、智慧城市、遠程醫療、…

Python(Pandas)數據分析學習

1.Pandas基本構成 引入Pandas import pandas as pd 1.Series 行 對應Excel中的一行數據,一維數據 定義Series # 第一個參數是具體數據 # 第二個參數的對應的索引下標 # 第三個參數的行名稱 data pd.Series([1,2,3,4,5], index[a,b,c,d,e], namedata) print(d…

我用Ai學Android Jetpack Compose之Card

這篇學習一下Card。回答來自 通義千問。 我想學習Card,麻煩你介紹一下 當然可以!在 Jetpack Compose 中,Card 是一個非常常用的組件,用于創建帶有陰影和圓角的卡片式布局。它可以幫助你輕松實現美觀且一致的 UI 設計&#xff0c…

圖漾相機——C++語言屬性設置

文章目錄 前言1.SDK API功能介紹1.1 Device組件下的API測試1.1.1 相機工作模式設置(TY_TRIGGER_PARAM_EX)1.1.2 TY_INT_FRAME_PER_TRIGGER1.1.3 TY_INT_PACKET_DELAY1.1.4 TY_INT_PACKET_SIZE1.1.5 TY_BOOL_GVSP_RESEND1.1.6 TY_BOOL_TRIGGER_OUT_IO1.1.…

STM32 TIM定時器配置

TIM簡介 TIM(Timer)定時器 定時器可以對輸入的時鐘進行計數,并在計數值達到設定值時觸發中斷 16位計數器、預分頻器、自動重裝寄存器的時基單元,在72MHz計數時鐘下可以實現最大59.65s的定時 不僅具備基本的定時中斷功能&#xff…

pytorch實現基于Word2Vec的詞嵌入

PyTorch 實現 Word2Vec(Skip-gram 模型) 的完整代碼,使用 中文語料 進行訓練,包括數據預處理、模型定義、訓練和測試。 1. 主要特點 支持中文數據,基于 jieba 進行分詞 使用 Skip-gram 進行訓練,適用于小數…

【數據結構】_鏈表經典算法OJ(力扣/牛客第二彈)

目錄 1. 題目1:返回倒數第k個節點 1.1 題目鏈接及描述 1.2 解題思路 1.3 程序 2. 題目2:鏈表的回文結構 2.1 題目鏈接及描述 2.2 解題思路 2.3 程序 1. 題目1:返回倒數第k個節點 1.1 題目鏈接及描述 題目鏈接: 面試題 …