欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Rust常用特型之ToOwned特型示例詳解

 更新時(shí)間:2024年04月22日 09:32:23   作者:AiMateZero  
在Rust中,假定某類型實(shí)現(xiàn)了Clone特型,如果給你一個(gè)對它引用,那我們得到它指向內(nèi)容的備份的最常見方式是調(diào)用其clone()函數(shù),這篇文章主要介紹了Rust常用特型之ToOwned特型,需要的朋友可以參考下

在Rust標(biāo)準(zhǔn)庫中,存在很多常用的工具類特型,它們能幫助我們寫出更具有Rust風(fēng)格的代碼。

ToOwned

這次我們來學(xué)一個(gè)和Borrow特型相關(guān)的特型,叫ToOwned類型??醋置嬉馑?code>Borrow是代表借出,而ToOwned代表去擁有它。

在Rust中,假定某類型實(shí)現(xiàn)了Clone特型,如果給你一個(gè)對它引用,那我們得到它指向內(nèi)容的備份的最常見方式是調(diào)用其clone()函數(shù)。但是如果你想克隆&str或者&[i32]時(shí)會發(fā)生什么呢?你的目的可能是想得到一個(gè)String或者Vec<i32>。但是根據(jù)Clone特型的定義,你無法得到它們。根據(jù)定義,對一個(gè)&T調(diào)用clone() 會返回一個(gè)T的值,也就是說會返回str或者[i32]。而我們前面學(xué)習(xí)Sized特型的時(shí)候提到過,str或者[i32] 是切片類型,無固定大小,是不能保存在變量中或者作為函數(shù)結(jié)果返回的。

std::borrow::ToOwned 特型提供了一個(gè)稍微寬松的方法將一引用轉(zhuǎn)換為可擁有的值。

trait ToOwned {
  type Owned: Borrow<Self>;
  fn to_owned(&self) -> Self::Owned;
}

上面的定義中,to_owned函數(shù)返回一個(gè)類型為Self::Owned的新鮮值,但是這個(gè)Owned可不是任意類型,它有個(gè)類型約束,也就是實(shí)現(xiàn)了Borrow<Self>. 也就是說A能借出B/&B(實(shí)現(xiàn)了Borrow<B>),B才能擁有A.

例如,你可以從Vec<T>中借出一個(gè)&[T](這里的泛型U 為 [T] ),因此[T]可以實(shí)現(xiàn)ToOwned<Owned=Vec<T>>,只要T實(shí)現(xiàn)了Clone特型。這里為什么要對T限制呢?畢竟你要得到一個(gè)備份,如果一個(gè)T不能克隆,那么這個(gè)備份是無法實(shí)現(xiàn)的,因?yàn)樾枰亚衅脑貜?fù)制到新的向量中去。相似的,str實(shí)現(xiàn)了ToOwned<Owned=String>,因此我們可以調(diào)用&strto_owned函數(shù)得到一個(gè)全新的字符串。Path也實(shí)現(xiàn)了ToOwned<Owned=PathBuf>,我們也可以從Path引用中得到一個(gè)全新的PathBuf值。

Humble Cow

BorrowToOwned聯(lián)動可以實(shí)現(xiàn)一個(gè)很有意思的類型,Cow,注意它不是奶牛的意思,而是指 clone on write 我們趁熱來學(xué)習(xí)它。

充分利用 Rust 需要深思熟慮所有權(quán)問題,例如某個(gè)函數(shù)是否應(yīng)該通過引用或值接收參數(shù)。通常你能確定使用其中的一種或者另一種(使用引用還是值),函數(shù)的參數(shù)類型代表了你的決定。但是存在這樣一些場景,你只有在運(yùn)行時(shí)才知道到底是需要借用還是引用,這時(shí),std::borrow::Cow類型就派上用場了,它的定義如下:

enum Cow<'a, B: ?Sized>
  where B: ToOwned
  {
  Borrowed(&'a B),
  Owned(<B as ToOwned>::Owned),
}

這里可以看到,Cow是一個(gè)枚舉,有兩個(gè)變量,分別代表借用和擁有。其Borrow變量綁定了一個(gè)&B(這里先忽視生命周期標(biāo)記),這個(gè)B是個(gè)泛型,它的約束為B: ToOwned。它的目標(biāo)類型我們先假定為U,那么U 必定實(shí)現(xiàn)了Borrow<B>

它的第二個(gè)枚舉變量為Owned,綁定了一個(gè)<B as ToOwned>::Owned的值,也就是U的值,所以Owned變量可以寫成Owned<U>。其中可以從U借出B,當(dāng)然,也可以從B擁有U的新值。

第一個(gè)枚舉變量,是綁定了&B,因此我們可以很方便的得到&B,第二個(gè)變量,是綁定了U,然而U又可以借出B,因此我們?nèi)匀豢梢院苋菀椎牡玫?code>&B( 通過U的borrow() 函數(shù))。兩個(gè)變量都可以方便的得到&B,因此它也實(shí)現(xiàn)了Deref特型,這樣你可以直接在Cow上調(diào)用B的相關(guān)函數(shù),而不管Cow是借用了B還是擁有了U。

你還可以在Cow類型的值上調(diào)用to_mut函數(shù)得到一個(gè)&mut B。 如果Cow變量剛好好Borrowed,則to_mut函數(shù)會先調(diào)用&Bto_owned方法得到它自己擁有的一個(gè)U的Copy,并對原來的變量進(jìn)行重新賦值,這樣就從Borrowed變量轉(zhuǎn)換成了Owned變量,然后再從新?lián)碛械腢的值中借出一個(gè)mut 引用。這里正是clone on write的含義所在(寫時(shí)clone).

我們來看一下這個(gè)Deref的實(shí)現(xiàn)代碼:

#[stable(feature = "rust1", since = "1.0.0")]
impl<B: ?Sized + ToOwned> Deref for Cow<'_, B>
where
    B::Owned: Borrow<B>,
{
    type Target = B;
    fn deref(&self) -> &B {
        match *self {
            Borrowed(borrowed) => borrowed,
            Owned(ref owned) => owned.borrow(),
        }
    }
}

你代碼中我們可以看到,如果Cow是引用 ,直接將這個(gè)引用返回,如果是擁有的U值,則從U值借出,這里有一個(gè)細(xì)節(jié):

Owned(ref owned) => owned.borrow(), 因?yàn)槲覀兊膁eref函數(shù)接收參數(shù)為&self,因此我們無法在函數(shù)內(nèi)部消耗掉Cow本身,而match直接匹配時(shí)便會消耗這個(gè)值,因此為了阻止這種行為,添加了ref owned,代表這個(gè)owned只是獲取一個(gè)引用 ,因此這里的owned的類型其實(shí)為&U,所以直接調(diào)用其borrow()函數(shù)也就得到了一個(gè)&B. 注意borrow函數(shù)也是接收一個(gè)引用而非值作為參數(shù)。

to_mut函數(shù)的解釋為:

Acquires a mutable reference to the owned form of the data.

Clones the data if it is not already owned.

使用示例為:

use std::borrow::Cow;
let mut cow = Cow::Borrowed("foo");
cow.to_mut().make_ascii_uppercase();
assert_eq!(
  cow,
  Cow::Owned(String::from("FOO")) as Cow<'_, str>
);

通過上面的示例我們可以看到,就算我們的cow是Borrowed變量,擁有一個(gè)共享的引用,到最后也變成了一個(gè)Owned變量。

我們來看一下實(shí)現(xiàn)過程:

#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
    match *self {
        Borrowed(borrowed) => {
            *self = Owned(borrowed.to_owned());
            match *self {
                Borrowed(..) => unreachable!(),
                Owned(ref mut owned) => owned,
            }
        }
        Owned(ref mut owned) => owned,
    }
}

這里 如果是Borrowed,則首先會to_owned得到U的一個(gè)新值,然后再將self重新賦值為Owned,然后再重新對self進(jìn)行match操作,

此時(shí)已經(jīng)是一個(gè)Owned,所以直接借出了ref mut,注意因?yàn)閙atch操作會消耗值,所以這里的Owned(ref mut owned) => owned, 中加了ref 代表是一個(gè)引用,結(jié)合上例,我們就得到了一個(gè)&mut String。

相似的,Cow也實(shí)現(xiàn)了into_owned方法將引用轉(zhuǎn)換為一個(gè)擁有的值。如果必須,則可以將值的所有權(quán)轉(zhuǎn)移給調(diào)用者,在這個(gè)過程中Cow本身的值會被消耗掉。

Cow一個(gè)常見的用法是返回一個(gè)靜態(tài)的字符串文字值常量或者一個(gè)動態(tài)的字符串。例如,假定你需要將一個(gè)枚舉類型轉(zhuǎn)換成一個(gè)消息,枚舉的大多數(shù)變量都可用于固定的字符串,但是有一些變量或者一些額外的信息,因此你可以返回一個(gè)Cow<'static str>。

use std::path::PathBuf;
use std::borrow::Cow;
fn describe(error: &Error) -> Cow<'static, str> {
  match *error {
      Error::OutOfMemory => "out of memory".into(),
      Error::StackOverflow => "stack overflow".into(),
      Error::MachineOnFire => "machine on fire".into(),
      Error::Unfathomable => "machine bewildered".into(),
      Error::FileNotFound(ref path) => {
      format!("file not found: {}", path.display()).into()
    }
  }
}

上面的代碼使用了CowInto特型實(shí)現(xiàn)來構(gòu)造值。這里其實(shí)是CowFrom實(shí)現(xiàn),然后相對應(yīng)的&str就有了Into實(shí)現(xiàn)。這個(gè)Match的絕大多數(shù)分支都返回一個(gè)靜態(tài)分配的文字串文本用于Cow::Borrowed綁定,只有最后一個(gè)分支返回一個(gè)String用于Owned變量綁定。

describe函數(shù)的調(diào)用者不用管返回的到底Cow的哪個(gè)變量,它只用簡單的將返回值看成是&str就行了,例如:

println!("Disaster has struck: {}", describe(&error));

如果你需要一個(gè)擁有的值,調(diào)用into_owned函數(shù)就可,例如 (describe(&error).into_owned() 就返回一個(gè)String。

使用Cow可以讓describle函數(shù)和它的調(diào)用者直到在需要時(shí)才會分配內(nèi)存來保存新生成的字符串。

到此這篇關(guān)于Rust常用特型之ToOwned特型的文章就介紹到這了,更多相關(guān)Rust ToOwned特型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • Rust?編程語言中的所有權(quán)ownership詳解

    Rust?編程語言中的所有權(quán)ownership詳解

    這篇文章主要介紹了Rust?編程語言中的所有權(quán)ownership詳解的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • Rust 的 into_owned() 方法實(shí)例詳解

    Rust 的 into_owned() 方法實(shí)例詳解

    into_owned是Rust語言中std::borrow::Cow 枚舉的一個(gè)方法,into_owned確保了調(diào)用者獲得數(shù)據(jù)的獨(dú)立所有權(quán),無論Cow之前是引用還是已經(jīng)擁有數(shù)據(jù),本文給大家介紹Rust 的 into_owned() 方法,感興趣的的朋友跟隨小編一起看看吧
    2024-03-03
  • Rust?搭建一個(gè)小程序運(yùn)行環(huán)境的方法詳解

    Rust?搭建一個(gè)小程序運(yùn)行環(huán)境的方法詳解

    rust是一門比較新的編程語言,2015年5月15日,Rust編程語言核心團(tuán)隊(duì)正式宣布發(fā)布Rust?1.0版本,本文給大家介紹Rust?搭建一個(gè)小程序運(yùn)行環(huán)境,以iOS?為例介紹開發(fā)環(huán)境的準(zhǔn)備,感興趣的朋友跟隨小編一起看看吧
    2022-05-05
  • Rust中的關(guān)聯(lián)類型總結(jié)

    Rust中的關(guān)聯(lián)類型總結(jié)

    關(guān)聯(lián)類型是定義通用trait的一種機(jī)制。它允許在trait中定義一個(gè)或多個(gè)占位符類型,這些類型將在trait的實(shí)現(xiàn)中具體化。文中有詳細(xì)示例代碼供參考,需要的朋友可以閱讀一下
    2023-05-05
  • Rust語言數(shù)據(jù)類型的具體使用

    Rust語言數(shù)據(jù)類型的具體使用

    在Rust中,每個(gè)值都有一個(gè)明確的數(shù)據(jù)類型,本文主要介紹了Rust語言數(shù)據(jù)類型的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-04-04
  • Rust 中的 Packages 與 Crates模塊化構(gòu)建的基礎(chǔ)及開發(fā)流程

    Rust 中的 Packages 與 Crates模塊化構(gòu)建的基礎(chǔ)及開發(fā)流程

    Rust中的Crate是編譯器處理的最小代碼單元,可以是二進(jìn)制或庫,每個(gè)Crate由一個(gè)CrateRoot文件(通常是src/main.rs或src/lib.rs)定義,本文給大家介紹Rust 中的 Packages 與 Crates模塊化構(gòu)建的基礎(chǔ)及開發(fā)流程,感興趣的朋友一起看看吧
    2025-02-02
  • Rust多線程Web服務(wù)器搭建過程

    Rust多線程Web服務(wù)器搭建過程

    這篇文章主要介紹了Rust多線程 Web 服務(wù)器搭建過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Rust讀取配置文件的實(shí)現(xiàn)

    Rust讀取配置文件的實(shí)現(xiàn)

    本文主要介紹了Rust讀取配置文件的實(shí)現(xiàn),主要讀取Cargo.toml文件,讀取.env文件和讀取自定義toml文件這三種,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Rust文本處理快速入門

    Rust文本處理快速入門

    編程過程中有許多類型的數(shù)據(jù)要處理,其中文本處理必不可少,本文主要介紹了Rust文本處理快速入門 ,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • Rust 模式匹配示例詳解

    Rust 模式匹配示例詳解

    這篇文章主要為大家介紹了Rust 模式匹配示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10

最新評論