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

rust類型轉(zhuǎn)換的實(shí)現(xiàn)

 更新時間:2023年12月07日 10:23:25   作者:zy010101  
Rust是類型安全的語言,因此在Rust中做類型轉(zhuǎn)換不是一件簡單的事,本文主要介紹了rust類型轉(zhuǎn)換的實(shí)現(xiàn),具有一定的參考價值,感興趣的可以了解一下

Rust 是類型安全的語言,因此在 Rust 中做類型轉(zhuǎn)換不是一件簡單的事。

as轉(zhuǎn)換

Rust 不提供原生類型之間的隱式類型轉(zhuǎn)換(coercion),但可以使用 as 關(guān)鍵字進(jìn)行顯式類型轉(zhuǎn)換(casting)。例如:

fn main() {
    cast();
}

// as 進(jìn)行的顯示類型強(qiáng)制轉(zhuǎn)換
fn cast() {
    let n: u8 = 123;
    let m: i32 = n as i32;      // 將u8強(qiáng)制轉(zhuǎn)換為i32類型

    println!("u8({})轉(zhuǎn)i32({})", n, m);

    let a = 12345;         // 整型字面值常量是i32類型
    let b: i8 = a as i8;        // 能容納更大數(shù)值的類型i32轉(zhuǎn)容納范圍較小的i8,存在數(shù)據(jù)溢出的風(fēng)險。

    println!("i32({})轉(zhuǎn)i8({})", a, b);

    let c = '我';          // char類型
    let d = c as u32;

    println!("char({})轉(zhuǎn)u32({})", c, d);       

    let f = 100u8;      
    let h = f as char;      // 只有u8才能轉(zhuǎn)char(相當(dāng)于只支持ASCII碼的值和字符轉(zhuǎn)換)

    println!("u8({})轉(zhuǎn)char({})", f, h);

    let f = 123.123;    
    let q = f as i32;
    println!("f64({})轉(zhuǎn)i32({})", f, q);


    let mut num = [1, 2, 3];
    let mut y = num.as_mut_ptr();       // 可變的指針類型
    let mut p = y as usize;                // 把指針轉(zhuǎn)為usize類型
    p += 4;                                       // 指針步進(jìn)一步(i32類型占4字節(jié),因此加4即可)
    y = p as *mut i32;                            // 將 usize轉(zhuǎn)為指針
    
    unsafe {                                        
        println!("{}", *y);                       // 在unsafe模塊中操作指針
    }
}

轉(zhuǎn)換不具有傳遞性 就算 e as U1 as U2 是合法的,也不能說明 e as U2 是合法的(e 不能直接轉(zhuǎn)換成 U2)。as轉(zhuǎn)換基本上只用于數(shù)值類型之間的轉(zhuǎn)換。而且需要注意,當(dāng)你從可以容納范圍更大的數(shù)據(jù)類型向可以容納范圍較小的數(shù)據(jù)類型轉(zhuǎn)換的時候會發(fā)生溢出,因此你要人為保證數(shù)據(jù)轉(zhuǎn)換是正確的。

into和from

From 和 Into 兩個 trait 是內(nèi)部相關(guān)聯(lián)的,實(shí)際上這是它們實(shí)現(xiàn)的一部分。如果我們能夠從類型 B 得到類型 A,那么很容易相信我們也能夠把類型 B 轉(zhuǎn)換為類型 A。

From

From trait 允許一種類型定義 “怎么根據(jù)另一種類型生成自己”,因此它提供了一種類型轉(zhuǎn)換的簡單機(jī)制。在標(biāo)準(zhǔn)庫中有無數(shù) From 的實(shí)現(xiàn),規(guī)定原生類型及其他常見類型的轉(zhuǎn)換功能。

比如,可以很容易地把 str 轉(zhuǎn)換成 String:

let s = String::from("qwert");
println!("s={s}");

也可以為我們自己的類型定義轉(zhuǎn)換機(jī)制:

#[derive(Debug)]
#[allow(unused)]
struct Number {
    value: i32,
}

impl From<i32> for Number {
    fn from(item: i32) -> Self {
        Number { value: item }
    }
}

let num = Number::from(30);
println!("My number is {:?}", num);

Into

Into trait 就是把 From trait 倒過來而已。也就是說,如果你為你的類型實(shí)現(xiàn)了 From,那么同時你也就免費(fèi)獲得了 Into。

使用 Into trait 通常要求指明要轉(zhuǎn)換到的類型,因?yàn)榫幾g器大多數(shù)時候不能推斷它。不過考慮到我們免費(fèi)獲得了 Into,這點(diǎn)代價不值一提。

// 需要指明轉(zhuǎn)換到的類型是Number
let a: Number = 1.into();
println!("My number is {:?}", a);

TryInto和TryFrom

類似于 From 和 Into,TryFrom 和 TryInto 是類型轉(zhuǎn)換的通用 trait。不同于 From/Into 的是,TryFrom 和 TryInto trait 用于易出錯的轉(zhuǎn)換,也正因如此,其返回值是 Result 型。

pub fn catsing(){
    let b = 123;
    let a: u8 = b.try_into().unwrap();          // try_into
    println!("{a}");

    let b:i32 = 12345;                // 有一點(diǎn)非常奇怪,那就是必須顯示聲明b的類型,否則編譯器無法推斷e的類型,導(dǎo)致錯誤。
    let _a: u8 = match b.try_into() {           // try_into
        Ok(v) => v,
        Err(e) => {
            println!("{:?}", e.to_string());
            0
        }
    };
}

如果我們需要自己實(shí)現(xiàn)try_from和try_into方法,那么需要實(shí)現(xiàn)TryFrom trait即可。例如:

#[derive(Debug, PartialEq)]
struct EvenNumber(i32);

impl TryFrom<i32> for EvenNumber {
    type Error = ();
    fn try_from(value: i32) -> Result<Self, Self::Error> {
        if value % 2 == 0 {
            Ok(EvenNumber(value))
        } else {
            Err(())
        }
    }
}

// TryFrom
assert_eq!(EvenNumber::try_from(8), Ok(EvenNumber(8)));
assert_eq!(EvenNumber::try_from(5), Err(()));

// TryInto
let result: Result<EvenNumber, ()> = 8i32.try_into();
assert_eq!(result, Ok(EvenNumber(8)));
let result: Result<EvenNumber, ()> = 5i32.try_into();
assert_eq!(result, Err(()));

ToString 和 FromStr

上面的這些轉(zhuǎn)換適大多數(shù)時候不適合字符串。它更需要ToString

Display

要把任何類型轉(zhuǎn)換成 String,只需要實(shí)現(xiàn)那個類型的 ToString trait。然而不要直接這么做,您應(yīng)該實(shí)現(xiàn)fmt::Display trait,它會自動提供 ToString,并且還可以用來打印類型。

pub fn format_string() {
    use std::fmt;

    struct Circle {
        radius: i32
    }

    impl fmt::Display for Circle {      // 為 Circle 實(shí)現(xiàn) Display trait
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Circle of radius {}", self.radius)
        }
    }

    let circle = Circle { radius: 6 };
    println!("{}", circle.to_string());     // to_string是由Display trait實(shí)現(xiàn)的。
}

當(dāng)然了,也可以實(shí)現(xiàn)ToString trait。例如:

pub fn to_stirng() {
    struct Circle {
        radius: i32
    }

    impl ToString for Circle {
        fn to_string(&self) -> String {
            format!("Circle of radius {:?}", self.radius)
        }
    }

    let circle = Circle { radius: 6 };
    println!("{}", circle.to_string());
}

字符串轉(zhuǎn)數(shù)字

只要對目標(biāo)類型實(shí)現(xiàn)了 FromStr trait,就可以用 parse 把字符串轉(zhuǎn)換成目標(biāo)類型。 標(biāo)準(zhǔn)庫中已經(jīng)給無數(shù)種類型實(shí)現(xiàn)了 FromStr。如果要轉(zhuǎn)換到用戶定義類型,只要手動實(shí)現(xiàn) FromStr 就行。
我們得提供要轉(zhuǎn)換到的類型,這可以通過顯示聲明類型,或者用 “渦輪魚” 語法(turbo fish,<>)實(shí)現(xiàn)。例如:

pub fn string_to_number(){
    let num = "12345";
    let num = num.parse::<i32>().unwrap();      // turbo fish寫法
    println!("{}", num);

    let num = "12345";
    let num: u64 = num.parse().unwrap();            // 顯示聲明類型寫法
    println!("{}", num);
}

點(diǎn)操作符

方法調(diào)用的點(diǎn)操作符看起來簡單,實(shí)際上非常不簡單,它在調(diào)用時,會發(fā)生很多魔法般的類型轉(zhuǎn)換,例如:自動引用、自動解引用,強(qiáng)制類型轉(zhuǎn)換直到類型能匹配等。

假設(shè)有一個方法 foo,它有一個接收器(接收器就是 self、&self、&mut self 參數(shù))。如果調(diào)用 value.foo(),編譯器在調(diào)用 foo 之前,需要決定到底使用哪個 Self 類型來調(diào)用?,F(xiàn)在假設(shè) value 擁有類型 T。再進(jìn)一步,我們使用完全限定語法來進(jìn)行準(zhǔn)確的函數(shù)調(diào)用:

  • 首先,編譯器檢查它是否可以直接調(diào)用 T::foo(value),稱之為值方法調(diào)用
  • 如果上一步調(diào)用無法完成(例如方法類型錯誤或者特征沒有針對 Self 進(jìn)行實(shí)現(xiàn),上文提到過特征不能進(jìn)行強(qiáng)制轉(zhuǎn)換),那么編譯器會嘗試增加自動引用,例如會嘗試以下調(diào)用: <&T>::foo(value) 和 <&mut T>::foo(value),稱之為引用方法調(diào)用
  • 若上面兩個方法依然不工作,編譯器會試著解引用 T ,然后再進(jìn)行嘗試。這里使用了 Deref 特征 —— 若 T: Deref<Target = U> (T 可以被解引用為 U),那么編譯器會使用 U 類型進(jìn)行嘗試,稱之為解引用方法調(diào)用
  • 若 T 不能被解引用,且 T 是一個定長類型(在編譯器類型長度是已知的),那么編譯器也會嘗試將 T 從定長類型轉(zhuǎn)為不定長類型,例如將 [i32; 2] 轉(zhuǎn)為 [i32]
  • 若還是不行,那么調(diào)用失敗

因此點(diǎn)操作符的背后是按照 值方法調(diào)用->引用方法調(diào)用->解引用方法調(diào)用->其它 的順序來進(jìn)行調(diào)用的。下面是一個例子:

fn do_stuff<T: Clone>(value: &T) {
    let cloned = value.clone();
}

上面例子中 cloned 的類型是什么?首先編譯器檢查能不能進(jìn)行值方法調(diào)用, value 的類型是 &T,同時 clone 方法的簽名也是 &T : fn clone(&T) -> T,因此可以進(jìn)行值方法調(diào)用,再加上編譯器知道了 T 實(shí)現(xiàn)了 Clone,因此 cloned 的類型是 T。

如果 T: Clone 的特征約束被移除呢?

fn do_stuff<T>(value: &T) {
    let cloned = value.clone();
}

首先,從直覺上來說,該方法會報錯,因?yàn)?T 沒有實(shí)現(xiàn) Clone 特征,但是真實(shí)情況是什么呢?

我們先來推導(dǎo)一番。 首先通過值方法調(diào)用就不再可行,因?yàn)?T 沒有實(shí)現(xiàn) Clone 特征,也就無法調(diào)用 T 的 clone 方法。接著編譯器嘗試引用方法調(diào)用,此時 T 變成 &T,在這種情況下, clone 方法的簽名如下: fn clone(&&T) -> &T,接著我們現(xiàn)在對 value 進(jìn)行了引用。 編譯器發(fā)現(xiàn) &T 實(shí)現(xiàn)了 Clone 類型(所有的引用類型都可以被復(fù)制,因?yàn)槠鋵?shí)就是復(fù)制一份地址),因此可以推出 cloned 也是 &T 類型。

最終,我們復(fù)制出一份引用指針,這很合理,因?yàn)橹殿愋?T 沒有實(shí)現(xiàn) Clone,只能去復(fù)制一個指針了。

下面是一個更復(fù)雜的例子:

#[derive(Clone)]
struct Container<T>(Arc<T>);

fn clone_containers<T>(foo: &Container<i32>, bar: &Container<T>) {
    let foo_cloned = foo.clone();
    let bar_cloned = bar.clone();
}

上面代碼中,Container<i32> 實(shí)現(xiàn)了 Clone 特征,因此編譯器可以直接進(jìn)行值方法調(diào)用,此時相當(dāng)于直接調(diào)用 foo.clone,其中 clone 的函數(shù)簽名是 fn clone(&T) -> T,由此可以看出 foo_cloned 的類型是 Container<i32>。

然而,bar_cloned 的類型卻是 &Container<T>。這是因?yàn)閐erive 宏最終生成的代碼大概如下所示:

impl<T> Clone for Container<T> where T: Clone {
    fn clone(&self) -> Self {
        Self(Arc::clone(&self.0))
    }
}

從上面代碼可以看出,派生 Clone 能實(shí)現(xiàn)的根本是 T 實(shí)現(xiàn)了Clone特征:where T: Clone, 因此 Container<T> 就沒有實(shí)現(xiàn) Clone 特征。

編譯器接著會去嘗試引用方法調(diào)用,此時 &Container<T> 引用實(shí)現(xiàn)了 Clone,最終可以得出 bar_cloned 的類型是 &Container<T>。

當(dāng)然,也可以為 Container<T> 手動實(shí)現(xiàn) Clone 特征:

impl<T> Clone for Container<T> {
    fn clone(&self) -> Self {
        Self(Arc::clone(&self.0))
    }
}

此時,編譯器首次嘗試值方法調(diào)用即可通過,因此 bar_cloned 的類型變成 Container<T>。

參考資料

 到此這篇關(guān)于rust類型轉(zhuǎn)換的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)rust類型轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何使用Rust的向量存儲值列表

    如何使用Rust的向量存儲值列表

    本文介紹了在Rust中使用向量存儲值列表的方法,包括創(chuàng)建、更新、讀取、遍歷、存儲多種類型以及內(nèi)存釋放等方面,向量是Rust中常用且強(qiáng)大的集合類型,熟練掌握其用法有助于編寫高效且安全的代碼
    2025-02-02
  • Rust在寫庫時實(shí)現(xiàn)緩存的操作方法

    Rust在寫庫時實(shí)現(xiàn)緩存的操作方法

    Moka是一個用于Rust的高性能緩存庫,它提供了多種類型的緩存數(shù)據(jù)結(jié)構(gòu),包括哈希表、LRU(最近最少使用)緩存和?支持TTL(生存時間)緩存,這篇文章給大家介紹Rust在寫庫時實(shí)現(xiàn)緩存的相關(guān)知識,感興趣的朋友一起看看吧
    2024-01-01
  • Rust 函數(shù)詳解

    Rust 函數(shù)詳解

    函數(shù)在 Rust 語言中是普遍存在的。Rust 支持多種編程范式,但更偏向于函數(shù)式,函數(shù)在 Rust 中是“一等公民”,函數(shù)可以作為數(shù)據(jù)在程序中進(jìn)行傳遞,對Rust 函數(shù)相關(guān)知識感興趣的朋友一起看看吧
    2021-11-11
  • Rust字符串字面值的一些經(jīng)驗(yàn)總結(jié)

    Rust字符串字面值的一些經(jīng)驗(yàn)總結(jié)

    字符串有兩種表現(xiàn)形式,一種是基本類型,表示字符串的切片,以&str表示,另一種是可變的string類型,下面這篇文章主要給大家介紹了關(guān)于Rust字符串字面值的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • 如何使用rust實(shí)現(xiàn)簡單的單鏈表

    如何使用rust實(shí)現(xiàn)簡單的單鏈表

    實(shí)現(xiàn)單鏈表在別的語言里面可能是一件簡單的事情,單對于Rust來說,絕對不簡單,下面這篇文章主要給大家介紹了關(guān)于如何使用rust實(shí)現(xiàn)簡單的單鏈表的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • Rust 入門之函數(shù)和注釋實(shí)例詳解

    Rust 入門之函數(shù)和注釋實(shí)例詳解

    這篇文章主要為大家介紹了Rust 入門之函數(shù)和注釋實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Rust 中的閉包之捕獲環(huán)境的匿名函數(shù)

    Rust 中的閉包之捕獲環(huán)境的匿名函數(shù)

    這篇文章介紹了Rust編程語言中的閉包,包括閉包的定義、使用、捕獲環(huán)境中的變量、類型推斷與注解、與函數(shù)的比較以及實(shí)際應(yīng)用,閉包具有捕獲環(huán)境、類型推斷和高效性等特性,是Rust中一個非常強(qiáng)大的工具,感興趣的朋友一起看看吧
    2025-02-02
  • Rust中引用的具體使用

    Rust中引用的具體使用

    在Rust語言中,引用機(jī)制是其所有權(quán)系統(tǒng)的重要組成部分,ust提供了兩種類型的引用,不可變引用和可變引用,本文就來詳細(xì)的介紹一下這兩種的用法,感興趣的可以了解一下
    2024-03-03
  • Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

    Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

    這篇文章主要介紹了Rust?use關(guān)鍵字妙用|模塊內(nèi)容拆分,文中還給大家介紹use關(guān)鍵字的習(xí)慣用法,快速引用自定義模塊內(nèi)容或標(biāo)準(zhǔn)庫,以此優(yōu)化代碼書寫,需要的朋友可以參考下
    2022-09-09
  • Rust?Atomics?and?Locks?源碼解讀

    Rust?Atomics?and?Locks?源碼解讀

    這篇文章主要為大家介紹了Rust?Atomics?and?Locks?源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02

最新評論