精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

為什么Borrow和BorrowMut被定義為泛型trait呢?

冬至子 ? 來源:山川與湖水 ? 作者:山川與湖水 ? 2023-05-22 15:57 ? 次閱讀

Borrow和BorrowMut trait 是Rust標準庫std:borrow 模塊中用于處理借用數據的trait,通過實現Borrow 和BorrowMut trait可以讓一個類型被借用成不同的引用。

1、AsRef VS Borrow 轉換與借用

Borrow trait的定義如下:

pub trait Borrow

對比一下 AsRef:

pub trait AsRef

可以看出AsRef的定義和Borrow的定義十分相像,那么既然有了AsRef trait,為啥還有Borrow trait的存在呢?

AsRef trait用來表示**類型轉換, **Borrow trait用來表示 借用數據, 在Rust中,為不同的語義不同的使用情況提供不同的類型表示是很常見的。

一個類型通過實現 Borrow trait,在 borrow()方法中提供對 T 的引用/借用,表達的語義是可以作為某個類型 T被借用,而非轉換。一個類型可以自由地借用為幾個不同的類型,也可以用可變的方式借用。

Borrow trait這類特性存在的意義旨在于解決特定領域的問題,例如在 Hashset,HashMap,BTreeSet,BtreeMap 中使用 &str 查詢 String 類型的鍵。

所以 Borrow 和 AsRef 如何選呢?

  • 當你想把不同類型的借用進行統一抽象,或者當你要建立一個數據結構,以同等方式處理自擁有值(ownered)和借用值(borrowed)時,例如散列(hash)和比較(compare)時,選擇Borrow。
  • 當你想把某個類型直接轉換為引用,并且你正在編寫通用代碼時,選擇AsRef。比較簡單的情況。

2、Borrow 和 BorrowMut 實現借用數據

BorrowMut trait的定義如下:

pub trait BorrowMut

BorrowMut trait類似于Borrow,用于可變借用。BorrowMut trait繼承自Borrowed trait。因此,一個類型如果實現了BorrowMut trait,則它也實現了Borrowed trait。

從Borrow trait的文檔中看,它對類型實現借用數據強加了更多的限制:

如果一個類型U實現了Borrow,在為U實現額外的trait(特別是實現Eq, Ord, Hash)的時候應該實現與T相同的行為。

這句話可以從例子理解,例如String實現了Borrow,那么在為String實現Eq, Ord, Hash等trait時,實現的行為應該與str實現相同。

Borrow trait的文檔中給了一個HashMap的例子,HashMap利用了String實現Borrow時,String和str對Eq, Hash的實現是相同的這一點,可以讓我們可以使用&str作為Key來訪問一個HashMap。HashMap的定義如下:

use std::borrow::Borrow;
use std:#:Hash;

pub struct HashMap

可以看到get方法的參數k類型是&Q,而不是&K。Q的trait bound是Hash + Eq + ?Sized,而K的trait bound是Borrow。這里K實現了Borrow, Hash, Eq等作為額外的trait,Borrow trait約定的限制是K和Q對這些額外trait的實現行為是相同的。

上面例子說明在寫通用的代碼時,如果依賴了Hash, Eq等這些額外的trait的相同的行為,會使用Borrow trait。這些trait作為trait bounds出現。

再看一個例子:

// 這個結構體能不能作為 HashMap 的 key?
pub struct CaseInsensitiveString(String);


// 它實現 Eq 沒有問題
impl PartialEq for CaseInsensitiveString {
    fn eq(&self, other: &Self) -> bool {
       // 但這里比較是要求忽略了 ascii 大小寫
        self.0.eq_ignore_ascii_case(&other.0)
    }
}


impl Eq for CaseInsensitiveString { }
// 實現 Hash 沒有問題
// 但因為 eq 忽略大小寫,那么 hash 計算也必須忽略大小寫
impl Hash for CaseInsensitiveString {
    fn hash

但是 CaseInsensitiveString 可以實現 Borrow嗎?

很顯然,CaseInsensitiveString 和 str 對 Hash 的實現不同,str 是不會忽略大小寫的。因此,CaseInsensitiveString不能實現Borrow,所以 CaseInsensitiveString 不能作為 HashMap 的 key,編譯器就可以通過 Borrow trait 來識別這種情況了。但是 CaseInsensitiveString 完全可以實現 AsRef 。這就是 Borrow 和 AsRef 的區別,Borrow 更加嚴格一些,并且表示的語義和 AsRef 完全不同。

3、Borrow和BorrowMut的blanket implement

對于BorrowBorrowMut,Rust為泛型T和&T自動實現了這兩個trait。

#[stable(feature = "rust1", since = "1.0.0")]
impl

4. 為什么Borrow和BorrowMut被定義為泛型trait

被定義為泛型trait,這樣就可以讓同一個類型同時有多個Borrow和BorrowMut trait的實現, 這樣這個類型就可以同時讓多個不同的引用類型作為它的借用。

例2:

fn main() {
    let s = String::from("hello");
    let s1: &str = s.borrow();
    let s2: &String = s.borrow();
    println!("s1: {s1:p}, s2: {s2:p}"); // s1: 0x7ff58ec05bc0, s2: 0x7ffee9169fe0
}

例2中引用類型&str&String都可以作為String類型的借用。即通過實現Borrow trait可以讓一個類型被借用成不同的引用。

總結

Borrow trait是用來表示 借用數據 ,一個類型通過實現 Borrow trait,在 borrow()方法中提供對 T 的引用/借用,表達的語義是可以作為某個類型 T被借用,而非轉換。一個類型可以自由地借用為幾個不同的類型,也可以用可變的方式借用。

1 如果一個類型實現了Borrow,那么這個類型的borrow方法可以從其借用一個&T。

2 可以將 BorrowBorrowMut視作 AsRefAsMut的嚴格版本,其返回的引用 &T 具有與 Self 相同的 Eq,Hash 和 Ord 的實現。

注:理解Borrow trait這類特性存在的意義,有助于我們揭開 HashSet,HashMap,BTreeSet 和 BTreeMap 中某些方法的實現的神秘面紗。但是在實際應用中,幾乎沒有什么地方需要我們去實現這樣的特性,因為再難找到一個需要我們對一個值再創造一個“借用”版本的類型的場景了。對于某種類型 T ,&T 就能解決 99.9% 的問題了,且 T: Borrow 已經被一攬子泛型實現對 T 實現了,所以我們無需手動實現它,也無需去實現某種的對 U 有 T: Borrow 了。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Hash算法
    +關注

    關注

    0

    文章

    43

    瀏覽量

    7380
  • rust語言
    +關注

    關注

    0

    文章

    57

    瀏覽量

    3006
收藏 人收藏

    評論

    相關推薦

    詳解Rust的

    所有的編程語言都致力于將重復的任務簡單化,并為此提供各種各樣的工具。在 Rust 中,(generics)就是這樣一種工具,它是具體類型或其它屬性的抽象替代。在編寫代碼時,我們可以直接描述
    發表于 11-12 09:08 ?1049次閱讀

    Rust中的From和Into trait的基礎使用方法和進階用法

    、可靠和安全的系統級應用的首選語言。 Rust中的From和Into是兩個重要的trait,它們可以幫助我們進行類型轉換。From trait允許我們從一個類型轉換到另一個類型,而Into trait則允許我們將一個類型轉換為另
    的頭像 發表于 09-20 10:55 ?1740次閱讀

    Java的背景和作用

    )只能存儲Object類型的對象,這使得在使用集合時需要進行強制類型轉換,容易出現類型錯誤。 的背景:在Java 5版本之前,Java的類型是靜態的,在編譯時確定,并且在運行時擦除類型信息。這種情況下,編譯器無法對集合的元素類型進行驗證,因此可能會導致運行時類型錯誤。
    的頭像 發表于 09-20 14:30 ?1050次閱讀
    Java<b class='flag-5'>泛</b><b class='flag-5'>型</b>的背景和作用

    labview連接mongdb問題,找到不.NET類中的

    有沒有人用labview連接mongodb數據庫的?已下載mongodb的c#驅動,利用labview中的.net控件調用相關函數,但是驅動中有部分函數在類中, labview能調用c#中的
    發表于 04-08 13:38

    冒泡排序法的實現

    冒泡排序法的實現,自用筆記!
    發表于 01-20 07:22

    iOS中關于的解析

    文章圍繞這五點: 1. 是什么 2. 為什么要用 3. 怎么用 4.
    發表于 09-25 10:01 ?0次下載

    java 編程

    一。 概念的提出(為什么需要)? 首先,我們看下下面這段簡短的代碼: publicclassGenericTest { publicstaticvoidmain(String[
    發表于 09-27 11:15 ?0次下載

    聊聊java實現的原理與好處

    摘要: 和C++以模板來實現靜多態不同,Java基于運行時支持選擇了,兩者的實現原理大相庭徑。C++可以支持基本類型作為模板參數,Java卻只能接受類作為參數;Java可以在
    發表于 09-27 16:50 ?0次下載

    Java的工作原理和案例

    是Java語言一個非常重要的概念,在Java集合類框架中被廣泛應用。在介紹之前先看一個例子。
    的頭像 發表于 07-01 10:14 ?2637次閱讀

    trait中使用 `async fn`

    trait 中使用?async fn async 工作組很高興地宣布?async fn?現在可以在 nightly 版本的 traits 中使用。在 playground 上有一個完整的工作示例
    的頭像 發表于 11-23 15:40 ?766次閱讀

    rust語言基礎學習: 智能指針之Cow

    Rust中與借用數據相關的三個trait: Borrow, BorrowMut和ToOwned。理解了這三個trait之后,再學習Rust中能夠實現寫時克隆的智能指針Cow
    的頭像 發表于 05-22 16:13 ?2868次閱讀

    rust語言基礎學習: Default trait

    Default trait 顧名思義是默認值,即Rust特定類型實現 Default 特性時,可以為該類型賦予了可選的默認值。
    的頭像 發表于 05-22 16:16 ?1250次閱讀

    實現Rust Trait類型 那么該類型的引用也實現了trait嗎?

    如果你在一個類型上實現了一個trait,然后引用了這個類型,那么類型的引用也實現了這個trait嗎?
    的頭像 發表于 08-28 15:25 ?676次閱讀

    C語言是否支持編程?

    C語言是否支持編程?毫無疑問,答案是不支持。
    的頭像 發表于 10-16 10:02 ?642次閱讀

    鴻蒙語言TypeScript學習第18天:【

    (Generics)是一種編程語言特性,允許在定義函數、類、接口等時使用占位符來表示類型,而不是具體的類型。
    的頭像 發表于 04-16 14:56 ?342次閱讀
    鴻蒙語言TypeScript學習第18天:【<b class='flag-5'>泛</b><b class='flag-5'>型</b>】