日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Rust 難點攻關,你學會了嗎?

來源: 責編: 時間:2023-10-10 18:30:43 278觀看
導讀當大家一路看到這里時,我敢說 90% 的人還是云里霧里的,例如你能說清楚:切片和切片引用的區別嗎?各種字符串之間的區別嗎?各種指針、引用的區別嗎?所有權轉移、拷貝、克隆的區別嗎?切片和切片引用關于 str / &str,[u8] / &[u8

當大家一路看到這里時,我敢說 90% 的人還是云里霧里的,例如你能說清楚:aBB28資訊網——每日最新資訊28at.com

  • 切片和切片引用的區別嗎?
  • 各種字符串之間的區別嗎?
  • 各種指針、引用的區別嗎?
  • 所有權轉移、拷貝、克隆的區別嗎?

aBB28資訊網——每日最新資訊28at.com

切片和切片引用

關于 str / &str,[u8] / &[u8] 區別,你能清晰的說出來嘛?如果答案是 No ,那就跟隨我一起來看看切片和切片引用到底有何區別吧。aBB28資訊網——每日最新資訊28at.com

在繼續之前,查看這里了解何為切片aBB28資訊網——每日最新資訊28at.com

切片允許我們引用集合中部分連續的元素序列,而不是引用整個集合。例如,字符串切片就是一個子字符串,數組切片就是一個子數組。aBB28資訊網——每日最新資訊28at.com

無法被直接使用的切片類型

Rust 語言特性內置的 str 和 [u8] 類型都是切片,前者是字符串切片,后者是數組切片,下面我們來嘗試下使用 str :aBB28資訊網——每日最新資訊28at.com

let string: str = "banana";

上面代碼創建一個 str 類型的字符串,看起來很正常,但是編譯就會報錯:aBB28資訊網——每日最新資訊28at.com

error[E0277]: the size for values of type `str` cannot be known at compilation time --> src/main.rs:4:9  |4 |     let string: str = "banana";  |         ^^^^^^ doesn't have a size known at compile-time

編譯器準確的告訴了我們原因:str 字符串切片它是 DST 動態大小類型,這意味著編譯器無法在編譯期知道 str 類型的大小,只有到了運行期才能動態獲知,這對于強類型、強安全的 Rust 語言來說是不可接受的。aBB28資訊網——每日最新資訊28at.com

也就是說,我們無法直接使用 str,而對于 [u8] 也是類似的,大家可以自己動手試試。aBB28資訊網——每日最新資訊28at.com

總之,我們可以總結出一個結論:在 Rust 中,所有的切片都是動態大小類型,它們都無法直接被使用。aBB28資訊網——每日最新資訊28at.com

為何切片是動態大小類型

原因在于底層的切片長度是可以動態變化的,而編譯器無法在編譯期得知它的具體的長度,因此該類型無法被分配在棧上,只能分配在堆上。aBB28資訊網——每日最新資訊28at.com

為何切片只能通過引用來使用

既然切片只能分配到堆上,我們就無法直接使用它,大家可以想想,所有分配在堆上的數據,是不是都是通過一個在棧上的引用來訪問的?切片也不例外。aBB28資訊網——每日最新資訊28at.com

為何切片引用可以存儲在棧上

切片引用是一個寬指針,存儲在棧上,指向了堆上的切片數據,該引用包含了切片的起始位置和長度,而且最重要的是,類似于指針,引用的大小是固定的(起始位置和長度都是整形),因此它才可以存儲在棧上。aBB28資訊網——每日最新資訊28at.com

有沒有可以存儲在棧上的

有,使用固定長度的數組: let a: [i8;4] = [1,2,3,4];,注意看,數組的類型與切片是不同的,前者的類型帶有長度:[i8;4],而后者僅僅是 [i8]。aBB28資訊網——每日最新資訊28at.com

切片引用

那么問題來了,該如何使用切片呢?aBB28資訊網——每日最新資訊28at.com

何以解憂,唯有引用。由于引用類型的大小在編譯期是已知的,因此在 Rust 中,如果要使用切片,就必須要使用它的引用。aBB28資訊網——每日最新資訊28at.com

str 切片的引用類型是 &str,而 [i32] 的引用類型是 &[i32],相信聰明的讀者已經看出來了,&str和 &[i32] 都是我們非常常用的類型,例如:aBB28資訊網——每日最新資訊28at.com

let s1: &str = "banana";let s2: &str = &String::from("banana");let arr = [1, 2, 3, 4, 5];let s3: &[i32] = &arr[1..3];

這段代碼就可以正常通過,原因在于這些切片引用的大小在編譯器都是已知的。aBB28資訊網——每日最新資訊28at.com

總結

我們常常說使用切片,實際上我們在用的是切片的引用,我們也在頻繁說使用字符串,實際上我們在使用的也是字符串切片的引用。aBB28資訊網——每日最新資訊28at.com

總之,切片在 Rust 中是動態大小類型 DST,是無法被我們直接使用的,而我們在使用的都是切片的引用。aBB28資訊網——每日最新資訊28at.com

切片aBB28資訊網——每日最新資訊28at.com

切片引用aBB28資訊網——每日最新資訊28at.com

str 字符串切片aBB28資訊網——每日最新資訊28at.com

&str 字符串切片的引用aBB28資訊網——每日最新資訊28at.com

[u8] 數組切片aBB28資訊網——每日最新資訊28at.com

&[u8] 數組切片的引用aBB28資訊網——每日最新資訊28at.com

但是出于方便,我們往往不會說使用切片引用,而是直接說使用字符串切片或數組切片,實際上,這時指代的都是切片的引用!aBB28資訊網——每日最新資訊28at.com

Eq 和 PartialEq

在 Rust 中,想要重載操作符,你就需要實現對應的特征。aBB28資訊網——每日最新資訊28at.com

例如 <、<=、> 和 >= 需要實現 PartialOrd 特征:aBB28資訊網——每日最新資訊28at.com

use std::fmt::Display;struct Pair<T> {    x: T,    y: T,}impl<T> Pair<T> {    fn new(x: T, y: T) -> Self {        Self { x, y }    }}impl<T: Display + PartialOrd> Pair<T> {    fn cmp_display(&self) {        if self.x >= self.y {            println!("The largest member is x = {}", self.x);        } else {            println!("The largest member is y = {}", self.y);        }    }}

再比如, + 號需要實現 std::ops::Add 特征,而本文的主角 Eq 和 PartialEq 正是 == 和 != 所需的特征,那么問題來了,這兩個特征有何區別?aBB28資訊網——每日最新資訊28at.com

我相信很多同學都說不太清楚,包括一些老司機,而且就算是翻文檔,可能也找不到特別明確的解釋。如果大家看過標準庫示例,可能會看過這個例子:aBB28資訊網——每日最新資訊28at.com

enum BookFormat { Paperback, Hardback, Ebook }struct Book {    isbn: i32,    format: BookFormat,}impl PartialEq for Book {    fn eq(&self, other: &Self) -> bool {        self.isbn == other.isbn    }}impl Eq for Book {}

這里只實現了 PartialEq,并沒有實現 Eq,而是直接使用了默認實現 impl Eq for Book {},奇了怪了,別急,還有呢:aBB28資訊網——每日最新資訊28at.com

impl PartialEq<IpAddr> for Ipv4Addr {    #[inline]    fn eq(&self, other: &IpAddr) -> bool {        match other {            IpAddr::V4(v4) => self == v4,            IpAddr::V6(_) => false,        }    }}impl Eq for Ipv4Addr {}

以上代碼來自 Rust 標準庫,可以看到,依然是這樣使用,類似的情況數不勝數。既然如此,是否說明如果要為我們的類型增加相等性比較,只要實現 PartialEq 即可?aBB28資訊網——每日最新資訊28at.com

其實,關鍵點就在于 partial 上,如果我們的類型只在部分情況下具有相等性,那你就只能實現 PartialEq,否則可以實現 PartialEq 然后再默認實現 Eq。aBB28資訊網——每日最新資訊28at.com

好的,問題逐步清晰起來,現在我們只需要搞清楚何為部分相等。aBB28資訊網——每日最新資訊28at.com

部分相等性

首先我們需要找到一個類型,它實現了 PartialEq 但是沒有實現 Eq(你可能會想有沒有反過來的情況?當然沒有啦,部分相等肯定是全部相等的子集?。?span style="display:none">aBB28資訊網——每日最新資訊28at.com

在 HashMap 章節提到過 HashMap 的 key 要求實現 Eq 特征,也就是要能完全相等,而浮點數由于沒有實現 Eq ,因此不能用于 HashMap 的 key。aBB28資訊網——每日最新資訊28at.com

當時由于一些知識點還沒有介紹,因此就沒有進一步展開,那么讓我們考慮浮點數既然沒有實現 Eq 為何還能進行比較呢?aBB28資訊網——每日最新資訊28at.com

fn main() {   let f1 = 3.14;   let f2 = 3.14;   if f1 == f2 {       println!("hello, world!");   }}

以上代碼是可以看到輸出內容的,既然浮點數沒有實現 Eq 那說明它實現了 PartialEq,一起寫個簡單代碼驗證下:aBB28資訊網——每日最新資訊28at.com

fn main() {    let f1 = 3.14;    is_eq(f1);    is_partial_eq(f1)}fn is_eq<T: Eq>(f: T) {}fn is_partial_eq<T: PartialEq>(f: T) {}

上面的代碼通過特征約束的方式驗證了我們的結論: aBB28資訊網——每日最新資訊28at.com

3 |     is_eq(f1);  |     ----- ^^ the trait `Eq` is not implemented for `{float}`

好的,既然我們成功找到了一個類型實現了 PartialEq 但沒有實現 Eq,那就通過它來看看何為部分相等性。aBB28資訊網——每日最新資訊28at.com

其實答案很簡單,浮點數有一個特殊的值 NaN,它是無法進行相等性比較的:aBB28資訊網——每日最新資訊28at.com

fn main() {    let f1 = f32::NAN;    let f2 = f32::NAN;    if f1 == f2 {        println!("NaN 竟然可以比較,這很不數學??!")    } else {        println!("果然,雖然兩個都是 NaN ,但是它們其實并不相等")    }}

大家猜猜哪一行會輸出 :) 至于 NaN 為何不能比較,這個原因就比較復雜了( 有讀者會說,其實就是你不知道,我只能義正嚴辭的說:咦?你怎么知道 :P )。aBB28資訊網——每日最新資訊28at.com

既然浮點數有一個值不可以比較相等性,那它自然只能實現 PartialEq 而不能實現 Eq 了,以此類推,如果我們的類型也有這種特殊要求,那也應該這么作。aBB28資訊網——每日最新資訊28at.com

Ord 和 PartialOrd

事實上,還有一對與 Eq/PartialEq 非常類似的特征,它們可以用于 <、<=、> 和 >= 比較,至于哪個類型實現了 PartialOrd 卻沒有實現 Ord 就交給大家自己來思考了:)aBB28資訊網——每日最新資訊28at.com

aBB28資訊網——每日最新資訊28at.com

瘋狂字符串

字符串讓人瘋狂,這句話用在 Rust 中一點都不夸張,不信?那你能否清晰的說出 String、str、&str、&String、Box<str> 或 Box<&str> 的區別?aBB28資訊網——每日最新資訊28at.com

Rust 語言的類型可以大致分為兩種:基本類型和標準庫類型,前者是由語言特性直接提供的,而后者是在標準庫中定義。即將登場的 str 類型就是唯一定義在語言特性中的字符串。aBB28資訊網——每日最新資訊28at.com

在繼續之前,大家需要先了解字符串的基本知識,本文主要在于概念對比,而不是字符串講解aBB28資訊網——每日最新資訊28at.com

str

如上所述,str 是唯一定義在 Rust 語言特性中的字符串,但是也是我們幾乎不會用到的字符串類型,為何?aBB28資訊網——每日最新資訊28at.com

原因在于 str 字符串它是 DST 動態大小類型,這意味著編譯器無法在編譯期知道 str 類型的大小,只有到了運行期才能動態獲知,這對于強類型、強安全的 Rust 語言來說是不可接受的。aBB28資訊網——每日最新資訊28at.com

let string: str = "banana";

上面代碼創建一個 str 類型的字符串,看起來很正常,但是編譯就會報錯:aBB28資訊網——每日最新資訊28at.com

error[E0277]: the size for values of type `str` cannot be known at compilation time --> src/main.rs:4:9  |4 |     let string: str = "banana";  |         ^^^^^^ doesn't have a size known at compile-time

如果追求更深層的原因,我們可以總結如下:所有的切片都是動態類型,它們都無法直接被使用,而 str就是字符串切片,[u8] 是數組切片。aBB28資訊網——每日最新資訊28at.com

同時還是 String 和 &str 的底層數據類型。由于 str 是動態aBB28資訊網——每日最新資訊28at.com

str 類型是硬編碼進可執行文件,也無法被修改,但是 String 則是一個可增長、可改變且具有所有權的 UTF-8 編碼字符串,當 Rust 用戶提到字符串時,往往指的就是 String 類型和 &str 字符串切片類型,這兩個類型都是 UTF-8 編碼。aBB28資訊網——每日最新資訊28at.com

除了 String 類型的字符串,Rust 的標準庫還提供了其他類型的字符串,例如 OsString, OsStr, CsString 和 CsStr 等,注意到這些名字都以 String 或者 Str 結尾了嗎?它們分別對應的是具有所有權和被借用的變量。aBB28資訊網——每日最新資訊28at.com

在 Rust 中,作用域、生命周期和 NLL(Non-Lexical Lifetimes,非詞法生命周期)是與內存管理和借用系統密切相關的概念。aBB28資訊網——每日最新資訊28at.com

1. 作用域(Scopes):

   在 Rust 中,每個變量都有自己的作用域,也就是變量的有效范圍。作用域可以是一個代碼塊(使用花括號 `{}` 包圍的代碼段)或一個函數。當變量超出其作用域時,它將被銷毀并釋放其占用的內存。這種方式確保了資源的正確釋放,避免了常見的內存泄漏和懸垂指針問題。aBB28資訊網——每日最新資訊28at.com

2. 生命周期(Lifetimes):

   生命周期是 Rust 中用于管理借用的機制。當一個變量借用另一個變量時,編譯器需要確保借用的變量在使用期間保持有效。生命周期注解(通常表示為 `'a`、`'b` 等)用于指定變量之間的依賴關系,以確保借用的有效性。生命周期注解描述了變量的最小有效范圍,編譯器使用它來進行靜態分析和驗證。aBB28資訊網——每日最新資訊28at.com

3. NLL(Non-Lexical Lifetimes):

 NLL 是 Rust 編譯器

在 Rust 中,`move`、`Copy` 和 `Clone` 是與變量所有權和復制相關的關鍵概念。aBB28資訊網——每日最新資訊28at.com

1. `move`:

   當將一個值賦值給另一個變量或將其作為函數參數傳遞時,Rust 會默認移動(move)該值的所有權。移動操作將轉移變量的所有權,原始變量將無法再訪問該值。這種方式避免了資源的重復釋放和懸垂指針問題。移動操作常見于將所有權轉移到函數中或從一個作用域轉移到另一個作用域。aBB28資訊網——每日最新資訊28at.com

2. `Copy`:

   `Copy` 是一個 trait(特質),用于標記可以通過簡單的位拷貝來復制的類型。當一個類型實現了 `Copy`,它的值可以在賦值或傳遞給函數時進行隱式的復制,而不會轉移所有權。`Copy` 類型的特點是在賦值或傳遞時不會發生所有權轉移,因此原始變量仍然可以訪問該值。常見的 `Copy` 類型包括整數、布爾值、浮點數以及一些固定大小的結構體和枚舉。aBB28資訊網——每日最新資訊28at.com

3. `Clone`:

   `Clone` 也是一個 trait,用于標記可以通過顯式克隆來復制的類型。與 `Copy` 不同,`Clone` 的復制是顯式的,需要調用 `clone()` 方法來創建一個新的拷貝。`Clone` 適用于需要深度復制的類型,它可以在需要時創建一個值的獨立拷貝,而不是共享相同的底層數據。需要注意的是,并非所有類型都實現了 `Clone`,因為深度復制可能涉及復雜的操作。aBB28資訊網——每日最新資訊28at.com

在 Rust 中,`move`、`Copy` 和 `Clone` 的使用取決于變量的所有權和復制需求。通過合理地使用這些概念,可以確保代碼的所有權轉移和復制操作是正確且高效的。aBB28資訊網——每日最新資訊28at.com

在 Rust 中,裸指針、引用和智能指針是用于處理內存和所有權的不同工具。aBB28資訊網——每日最新資訊28at.com

1. 裸指針(Raw Pointers):

   裸指針是直接操作內存地址的指針,沒有 Rust 的安全保證。在 Rust 中,裸指針分為不可變裸指針(`*const T`)和可變裸指針(`*mut T`)。裸指針可以用于以下情況:aBB28資訊網——每日最新資訊28at.com

   - 與外部代碼(如 C 代碼)進行交互。aBB28資訊網——每日最新資訊28at.com

   - 訪問未初始化的內存區域。aBB28資訊網——每日最新資訊28at.com

   - 實現某些不安全的數據結構和算法。aBB28資訊網——每日最新資訊28at.com

   使用裸指針需要謹慎,因為它們繞過了 Rust 的所有權和借用系統,容易導致內存安全問題。aBB28資訊網——每日最新資訊28at.com

2. 引用(References):

   引用是 Rust 中的安全指針,用于借用值而不獲取其所有權。引用分為不可變引用(`&T`)和可變引用(`&mut T`)。引用具有以下特點:aBB28資訊網——每日最新資訊28at.com

   - 引用是非空且始終有效的。aBB28資訊網——每日最新資訊28at.com

   - 引用遵循 Rust 的借用規則,保證了內存安全性。aBB28資訊網——每日最新資訊28at.com

   - 引用在編譯時檢查,不會導致運行時開銷。aBB28資訊網——每日最新資訊28at.com

   引用是 Rust 中常用的機制,用于實現借用檢查和避免數據競爭。aBB28資訊網——每日最新資訊28at.com

3. 智能指針(Smart Pointers):

   智能指針是包裝了堆上數據的結構,提供了額外的功能和語義。在 Rust 中,常見的智能指針有 `Box<T>`、`Rc<T>` 和 `Arc<T>`:aBB28資訊網——每日最新資訊28at.com

   - `Box<T>` 是在堆上分配內存并擁有唯一所有權的指針。aBB28資訊網——每日最新資訊28at.com

   - `Rc<T>` 是引用計數智能指針,可以在多個位置共享所有權。aBB28資訊網——每日最新資訊28at.com

   - `Arc<T>` 是原子引用計數智能指針,適用于并發環境。aBB28資訊網——每日最新資訊28at.com

   智能指針提供了內存管理、所有權傳遞、生命周期擴展和特定行為的能力,可以用于解決特定的問題和場景。aBB28資訊網——每日最新資訊28at.com

總結:裸指針用于低級別的操作,引用用于安全的借用,智能指針提供了更高級別的內存管理和所有權控制。在 Rust 中,推薦使用引用和智能指針來確保內存安全性和代碼可維護性。aBB28資訊網——每日最新資訊28at.com


aBB28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-12692-0.htmlRust 難點攻關,你學會了嗎?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: caliburn.micro日志打印,app.xaml里面如何配置?

下一篇: 五個JavaScript代碼優化優秀實踐

標簽:
  • 熱門焦點
  • 小米平板5 Pro 12.4簡評:多專多能 兼顧影音娛樂的大屏利器

    疫情帶來了網課,網課盤活了安卓平板,安卓平板市場雖然中途停滯了幾年,但好的一點就是停滯的這幾年行業又有了新的發展方向,例如超窄邊框、高刷新率、多攝鏡頭組合等,這就讓安卓
  • 三萬字盤點 Spring 九大核心基礎功能

    大家好,我是三友~~今天來跟大家聊一聊Spring的9大核心基礎功能。話不多說,先上目錄:圖片友情提示,本文過長,建議收藏,嘿嘿嘿!一、資源管理資源管理是Spring的一個核心的基礎功能,不
  • 一篇文章帶你了解 CSS 屬性選擇器

    屬性選擇器對帶有指定屬性的 HTML 元素設置樣式。可以為擁有指定屬性的 HTML 元素設置樣式,而不僅限于 class 和 id 屬性。一、了解屬性選擇器CSS屬性選擇器提供了一種簡單而
  • 微軟邀請 Microsoft 365 商業用戶,測試視頻編輯器 Clipchamp

    8 月 1 日消息,微軟近日宣布即將面向 Microsoft 365 商業用戶,開放 Clipchamp 應用,邀請用戶通過該應用來編輯視頻。微軟于 2021 年收購 Clipchamp,隨后開始逐步整合到 Microsof
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人員可能會涉及各種各樣的安全任務,包括但不限于:開發某些安全工具的插件,滿足自己特定的安全需求;自定義github搜索工具,快速查找所需的安全資料、漏洞poc、exp
  • 共享單車的故事講到哪了?

    來源丨海克財經與共享充電寶相差不多,共享單車已很久沒有被國內熱點新聞關照到了。除了一再漲價和用戶直呼用不起了。近日多家媒體再發報道稱,成都、天津、鄭州等地多個共享單
  • 華為Mate60系列模具曝光:采用碩大圓形后置相機模組+拼接配色方案

    據此前多方爆料,今年華為將開始恢復一年雙旗艦戰略,除上半年推出的P60系列外,往年下半年的Mate系列也將迎來更新,有望在9-10月份帶來全新的華為Mate60
  • OPPO K11評測:旗艦級IMX890加持 2000元檔最強影像手機

    【Techweb評測】中端機型用戶群體巨大,占了中國目前手機市場的大頭,一直以來都是各手機品牌的“必爭之地”,其中OPPO K系列機型一直以來都以高品質、
  • 榮耀Magic4 至臻版 首創智慧隱私通話 強勁影音系統

    2022年第一季度臨近尾聲,在該季度內,許多品牌陸續發布自己的最新產品,讓大家從全新的角度來了解當今的手機技術。手機是電子設備中,更新迭代十分迅速的一款產品,基
Top 主站蜘蛛池模板: 桃园县| 格尔木市| 布尔津县| 当涂县| 长丰县| 利辛县| 敖汉旗| 酒泉市| 富平县| 平阴县| 唐海县| 全椒县| 宝兴县| 丰原市| 宽甸| 肥西县| 连城县| 道孚县| 隆德县| 西藏| 齐齐哈尔市| 错那县| 周至县| 钦州市| 汕头市| 商南县| 新丰县| 新昌县| 宣武区| 永德县| 常宁市| 广德县| 赫章县| 乐陵市| 乌兰察布市| 图们市| 南和县| 安溪县| 洛南县| 嘉鱼县| 泸西县|