Rust 學習筆記:Box<T>

Rust 學習筆記:Box

  • Rust 學習筆記:Box<T\>
    • Box\<T> 簡介
    • 使用 Box\<T\> 在堆上存儲數據
    • 啟用帶有 box 的遞歸類型
      • 關于 cons 列表的介紹
      • 計算非遞歸類型的大小
      • 使用 Box\<T\> 獲取大小已知的遞歸類型

Rust 學習筆記:Box<T>

指針是在內存中包含地址的變量的一般概念。這個地址引用或“指向”其他一些數據。在 Rust 中最常見的指針類型是引用,由 & 符號表示,并借用它們所指向的值。除了引用數據之外,它們沒有任何特殊功能,也沒有開銷。

智能指針是一種像指針一樣的數據結構,但還具有額外的元數據和功能。Rust 在標準庫中定義了各種智能指針,這些指針提供的功能超出了引用所提供的功能。

具有所有權和借用概念的 Rust 在引用和智能指針之間有一個額外的區別:引用只借用數據,而在許多情況下,智能指針擁有它們所指向的數據。

我們遇到了一些智能指針:String 和 Vec<T>。這兩種類型都算作智能指針,因為它們擁有一些內存,并允許對其進行操作。它們還具有元數據和額外的功能或保證。例如,String 將其容量存儲為元數據,并具有確保其數據始終是有效的 UTF-8 的額外能力。

智能指針通常使用結構體實現。與普通結構體不同,智能指針實現了 Deref 和Drop trait。Deref trait 允許智能指針結構體的實例表現得像引用一樣,這樣就可以編寫代碼來使用引用或智能指針。Drop trait 允許自定義當智能指針的實例超出作用域時運行的代碼。

Box<T> 簡介

最直接的智能指針是 Box<T>,它運行將數據存儲在堆中而不是棧中,留在棧上的是指向堆數據的指針。

Box<T> 沒有性能開銷,但它們也沒有太多額外的功能。最常在以下情況下使用它:

  • 當你的類型在編譯時無法知道其大小,并且你希望在需要精確大小的上下文中使用該類型的值時

  • 當你有大量的數據,你想要轉移所有權,但要確保數據不會被復制時

  • 當你想擁有一個值,你只關心它是一個實現了特定特性的類型,而不是一個特定的類型

我們將在下文中演示第一種情況。在第二種情況下,傳輸大量數據的所有權可能需要很長時間,因為數據是在棧上復制的。為了在這種情況下提高性能,我們可以將大量數據存儲在堆中的盒子中。然后,只有少量的指針數據在棧上被復制,而它引用的數據留在堆上的一個地方。第三種情況被稱為 trait 對象,后續文章將專門討論了這個主題。

使用 Box<T> 在堆上存儲數據

首先介紹 Box<T> 的語法以及如何與存儲在 Box<T> 中的值進行交互。

fn main() {let b = Box::new(5);println!("b = {b}");
}

我們將變量 b 定義為具有指向值 5 的 box 的值,該值在堆上分配。這個程序將輸出 b = 5。在這種情況下,我們可以訪問 box 中的數據,就像我們訪問棧中的數據一樣。

當一個 box 超出作用域時,就像 main 語句末尾的 b 變量那樣,它將被釋放。對 box(存儲在棧上)和它所指向的數據(存儲在堆上)都進行釋放。

將單個值放在堆上并不是很有用,在棧上使用單個 i32 這樣的值更合適。

Box<T> 在定義類型時更有用。

啟用帶有 box 的遞歸類型

遞歸類型的值可以有另一個相同類型的值作為其本身的一部分。遞歸類型造成了一個問題,因為 Rust 需要在編譯時知道一個類型占用了多少空間。然而,遞歸類型的值的嵌套理論上可以無限地繼續下去,因此 Rust 無法知道值需要多少空間。因為 box 的大小是已知的,所以我們可以通過在遞歸類型定義中插入一個 box 來啟用遞歸類型。

作為遞歸類型的一個示例,讓我們研究一下 cons 列表。這是函數式編程語言中常見的一種數據類型。

關于 cons 列表的介紹

cons 列表是一種來自 Lisp 編程語言的數據結構,由嵌套對組成,是 Lisp 版本的鏈表。它的名字來自于 Lisp 中的c ons 函數(construct function 的縮寫),它從它的兩個參數構造一個新的 pair。通過對由一個值和另一個值組成的對調用 cons,我們可以構造由遞歸對組成的 cons 列表。

例如,下面是一個 cons 列表的偽代碼表示,其中包含列表 1、2、3,每一對都在括號中:

(1, (2, (3, Nil)))

cons 列表中的每一項包含兩個元素:當前項的值和下一項的值。列表中的最后一項只包含一個名為 Nil 的值,沒有下一項。

cons 列表不是Rust中常用的數據結構。但從本章的 cons 列表開始,我們可以探索 box 如何讓我們定義遞歸數據類型。

下列代碼包含了 cons 列表的枚舉定義。

enum List {Cons(i32, List),Nil,
}

注意,這段代碼還不能編譯,因為 List 類型沒有已知的大小,我們將對此進行演示。

嘗試構建一個 cons 列表:

use crate::List::{Cons, Nil};fn main() {let list = Cons(1, Cons(2, Cons(3, Nil)));
}

第一個 Cons 值保存 1 和另一個 List 值。這個 List 值是另一個 Cons 值,它包含 2 和另一 List 值。這個 List 值是另一個 Cons 值,它包含 3 和一個 List 值,最后是 Nil,這是表示列表結束的非遞歸變體。

嘗試運行這段代碼,報錯:

在這里插入圖片描述

錯誤顯示 List 類型“具有無限大小”。原因是我們用遞歸的變量定義了 List:它直接保存自身的另一個值。因此,Rust 無法計算出它需要多少空間來存儲 List 值。

讓我們分析一下為什么會出現這個錯誤。首先,我們來看一下 Rust 如何決定存儲非遞歸類型的值需要多少空間。

計算非遞歸類型的大小

以一個 Message 枚舉為例:

enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}

為了確定為 Message 值分配多少空間,Rust 遍歷每個變體,以查看哪個變體需要最多的空間。Message::Quit 不需要任何空間,Message::Move 占用兩個 i32 值大小的空間,以此類推。因為只使用一個變體,所以 Message 值所需的最大空間就是存儲其最大變體所需的空間。

與此形成對比的是,當 Rust 試圖確定 List 枚舉這樣的遞歸類型需要多少空間時發生的情況。編譯器首先查看 Cons 變量,它包含一個 i32 類型的值和一個 List 類型的值。因此,Cons 需要的空間量等于 i32 的大小加上 List 的大小。為了計算出 List 類型需要多少內存,編譯器從 Cons 變量開始,這個過程無限地繼續下去。

在這里插入圖片描述

使用 Box<T> 獲取大小已知的遞歸類型

因為 Rust 不能計算出為遞歸定義的類型分配多少空間,編譯器給出了一個錯誤,并給出了這個有用的建議:

在這里插入圖片描述

在這個建議中,間接意味著不是直接存儲一個值,而是通過存儲指向該值的指針來改變數據結構,從而間接存儲該值。

因為 Box<T> 是一個指針,指針的大小不會根據它所指向的數據量而改變。這意味著我們可以在 Cons 變量中放入 Box<T>,而不是直接放入另一個 List 值。Box<T> 將指向下一個 List 值,該值將位于堆上,而不是在 Cons 變量中。

從概念上講,我們仍然有一個列表,創建了包含其他列表的列表。但是這個實現現在更像是將項放在另一個項旁邊,而不是放在另一個項內部。

修改代碼:

enum List {Cons(i32, Box<List>),Nil,
}use crate::List::{Cons, Nil};fn main() {let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}

一個 Cons 變量 = 一個 i32 + 一個Box<T> 指針。Nil 不存儲任何值,因此它比 Cons 變量需要更少的空間。通過使用盒子,我們打破了無限的遞歸鏈,因此編譯器可以計算出存儲 List 值所需的大小。

在這里插入圖片描述

盒子只提供間接分配和堆分配,沒有任何其他特殊功能,也沒有這些特殊功能所帶來的性能開銷,因此它們在像 cons 列表這樣的情況下非常有用,其中間接是我們唯一需要的特性。

Box<T> 類型是一個智能指針,因為它實現了 Deref trait,它允許 Box<T> 值被當作引用來對待。當 Box<T> 值超出作用域時,由于 Drop trait 的實現,該指針所指向的堆數據也會被清理。

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

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

相關文章

英語寫作中“不少于(小于)”no less than替代no fewer than的用法

no less than 1 liter of water&#xff0c;no fewer than 100 people 是我們的傳統用法。現代英語有一個有趣的現象&#xff0c;就是less 代替fewer 形容可數名詞&#xff0c;例如&#xff1a; Do you have 10 courses each week? No. We have less. 顯然按嚴格語法應該是…

競品分析六大步驟

一、引言 在產品打磨、市場推廣或戰略定位過程中&#xff0c;我們常常會面臨一個關鍵任務——競品分析。一份系統的競品分析不僅能幫助我們知己知彼&#xff0c;優化產品策略&#xff0c;更能成為決策層制定方向的重要依據。競品分析到底該怎么做&#xff1f;今天我將結合自己的…

【Java Web】9.Maven高級

&#x1f4d8;博客主頁&#xff1a;程序員葵安 &#x1faf6;感謝大家點贊&#x1f44d;&#x1f3fb;收藏?評論?&#x1f3fb; 文章目錄 一、分模塊設計與開發 1.1 介紹 1.2 實踐 二、繼承與聚合 2.1 繼承 繼承關系 版本鎖定 2.2 聚合 2.3 繼承與聚合對比 三、…

MySQL 全量、增量備份與恢復

一.MySQL 數據庫備份概述 備份的主要目的是災難恢復&#xff0c;備份還可以測試應用、回滾數據修改、查詢歷史數據、審計等。之前已經學習過如何安裝 MySQL&#xff0c;本小節將從生產運維的角度了解備份恢復的分類與方法。 1 數據備份的重要性 在企業中數據的價值至關…

第六個微信小程序:教師工具集

源于工作需要&#xff0c;下面開始。 安裝及使用 | Taro 文檔 vscode 代碼管理 git 輔助 開發技術如上&#xff1a; 1.開始創建模板 taro4.1.1 $ taro init teachers-tools 2.用vsocde開始吧。 選擇 第二個文件夾找一。 (base) PS D:\react\teachers-tools> pnpm…

Linux 里 su 和 sudo 命令這兩個有什么不一樣?

《小菜狗 Linux 操作系統快速入門筆記》目錄&#xff1a; 《小菜狗 Linux 操作系統快速入門筆記》&#xff08;01.0&#xff09;文章導航目錄【實時更新】 Linux 是一個多用戶的操作系統。在 Linux 中&#xff0c;理論上來說&#xff0c;我們可以創建無數個用戶&#xff0c;但…

Elastic 獲得 AWS 教育 ISV 合作伙伴資質,進一步增強教育解決方案產品組合

作者&#xff1a;來自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通過搜索 AI 和云創新推動教育領域的數字化轉型。 我們非常高興地宣布&#xff0c;Elastic 已獲得 AWS 教育 ISV 合作伙伴資質。這一重要認證表明&#xff0c;Elastic 作為 …

服務器被攻擊了怎么辦

可以上一個高防IP或者AI云防護都是可以的。&#xff08;有效防御CC、APl接口、http、tcp、WEB應用掃描/爬蟲、SYN、WAF、DDOS、UDP、入侵、滲透、SQL注入、XSS跨站腳本攻擊、遠程惡意代碼執行、session fixation、Webshell攻擊、惡意請求&#xff0c;惡意掃描、暴力破解、CSRF等…

【學習筆記】Circuit Tracing: Revealing Computational Graphs in Language Models

Circuit Tracing: Revealing Computational Graphs in Language Models 替代模型(Replacement Model)&#xff1a;用更多的可解釋的特征來替代transformer模型的神經元。 歸因圖(Attribution Graph)&#xff1a;展示特征之間的相互影響&#xff0c;能夠追蹤模型生成輸出時所采用…

靈活控制,modbus tcp轉ethernetip的 多功能水處理方案

油田自動化和先進的油氣行業軟件為油氣公司帶來了諸多益處。其中包括&#xff1a; 1.自動化可以消除多余的步驟、減少人為錯誤并降低運行設備所需的能量&#xff0c;從而降低成本。 2.油天然氣行業不斷追求高水平生產。自動化可以更輕松地減少計劃外停機時間&#xff0c;從而…

是否存在路徑(FIFOBB算法)

題目描述 一個具有 n 個頂點e條邊的無向圖&#xff0c;該圖頂點的編號依次為0到n-1且不存在頂點與自身相連的邊。請使用FIFOBB算法編寫程序&#xff0c;確定是否存在從頂點 source到頂點 destination的路徑。 輸入 第一行兩個整數&#xff0c;分別表示n 和 e 的值&#xff08;1…

windows VeraCrypt – 磁盤加密工具

下載鏈接&#xff1a;夸克網盤分享 VeraCrypt一款跨平臺(Windows/Mac/Linux)的磁盤加密工具&#xff0c;提供多層級數據保護方案&#xff1a;虛擬加密盤&#xff1a;在文件中創建可掛載的加密虛擬磁盤全設備加密&#xff1a;支持分區/USB/硬盤等存儲設備的全盤加密系統盤加密&…

客戶體驗數據使用的三種視角——場景視角

當企業收集到大量的客戶體驗數據之后&#xff0c;應該如何應用&#xff1f;有哪些主要的使用場景和分析視角&#xff1f;體驗家團隊通過三篇文章&#xff0c;陸續介紹三種體驗數據的使用場景&#xff0c;以幫助企業更有效地利用體驗數據進行改進。 01 宏觀層次的“旅程視角” …

時序數據庫IoTDB的UDF Sample算法在數據監控、故障預防的應用

一、數據監控在工業物聯網中的重要性 設備數據監控是工業物聯網&#xff08;IoT&#xff09;中最為廣泛應用的領域之一。通過實時監控工廠機械設備的運行狀態&#xff0c;企業能夠提前發現設備的潛在故障&#xff0c;從而實現預防性維護與可預測性維護。這一做法不僅能有效提升…

fastadmin fildList 動態下拉框默認選中

html頁面 <td><select class"form-control dtselect" data-rule"required" data-dtselected"<%row.type%>" name"<%name%>[<%index%>][type]">{foreach nametypeList idvo}<option value"{$vo…

Python 入門到進階全指南:從語言特性到實戰項目

一、Python 簡介 Python 是一種高級、跨平臺、解釋型編程語言&#xff0c;以簡潔語法和高可讀性著稱&#xff0c;既適合編程初學者快速入門&#xff0c;也能滿足資深開發者的復雜需求。其核心特性與應用場景如下&#xff1a; 核心特性解析 解釋型語言&#xff1a;無需編譯即可…

【unity游戲開發入門到精通——通用篇】從零掌握UnityWebRequest:文件下載、表單提交、超時處理、斷點續傳

文章目錄 一、UnityWebRequest 與 WWW 的比較二、核心組件三、常用方法四、基本使用示例1. GET請求2. POST請求五、實用功能1. 下載進度顯示2. 斷點續傳實現3. 文件上傳到服務器六、使用建議七、性能優化專欄推薦完結一、UnityWebRequest 與 WWW 的比較 UnityWebRequest 是 Un…

使用 Flutter 開發 App 時,想要根據 Figma 設計稿開發出響應式 UI 界面

在使用 Flutter 開發 App 時&#xff0c;想要根據 Figma 設計稿開發出響應式 UI 界面&#xff08;Responsive UI&#xff09;&#xff0c;以適配不同尺寸和分辨率的手機設備&#xff0c;需要從 設計階段 和 編碼實現階段 雙向配合。以下是詳細的實現思路與方法&#xff1a; &am…

【計算機網絡】網絡層協議

1. ICMP協議的介紹及應用 IP協議的助手 —— ICMP 協議 ping 是基于 ICMP 協議工作的&#xff0c;所以要明白 ping 的工作&#xff0c;首先我們先來熟悉 ICMP 協議。 ICMP 全稱是 Internet Control Message Protocol&#xff0c;也就是互聯網控制報文協議。 里面有個關鍵詞 …

LabVIEW準分子激光器智能控制系統

LabVIEW 開發準分子激光器智能控制系統&#xff0c;針對放電激勵型準分子激光器強電磁干擾環境下的控制難題&#xff0c;采用 “PC 端 LabVIEW 人機交互 MCU 端實時控制 光纖隔離通信” 架構&#xff0c;實現激光能量閉環控制、腔體環境監測、氣路自動管理等功能。硬件選用 N…