溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Rust常用的標(biāo)準(zhǔn)庫工具有哪些

發(fā)布時(shí)間:2021-10-13 10:51:25 來源:億速云 閱讀:380 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“Rust常用的標(biāo)準(zhǔn)庫工具有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Rust常用的標(biāo)準(zhǔn)庫工具有哪些”吧!

Rust常用的標(biāo)準(zhǔn)庫工具有哪些

Prelude

我們一般使用use語句把其他模塊的內(nèi)容引入當(dāng)前模塊中,但對(duì)于標(biāo)準(zhǔn)庫中一些非常常用的工具,每次都寫use語句就過于冗余,因此標(biāo)準(zhǔn)庫提供了一個(gè)std::prelude模塊,在這個(gè)模塊中導(dǎo)出一些最常見的工具,然后編譯器為用戶編寫的每一個(gè)crate都自動(dòng)插入一句話:

use std::prelude::*;

如此,一些最常見的工具就可以直接使用,而無需use了。對(duì)這個(gè)std::prelude模塊所包含內(nèi)容的權(quán)衡是需要細(xì)致考量的,因?yàn)槿绻膬?nèi)容過多則會(huì)引入很多不被使用的工具,這反倒不美了。當(dāng)下的std::prelude模塊中包含的內(nèi)容在std::prelude::v1中。

類型轉(zhuǎn)換

除了as關(guān)鍵字可以用來進(jìn)行基本類型之間的轉(zhuǎn)換,Rust還提供了很多trait來實(shí)現(xiàn)自定義類型之間的轉(zhuǎn)換。

AsRef / AsMut

AsRef的含義是該類型可以通過調(diào)用as_ref方法得到另外一個(gè)類型的共享引用,同理,AsMut得到的是另外一個(gè)類型的可讀寫引用,它們的定義如下:

pub trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
}

pub trait AsMut<T: ?Sized> {
    fn as_mut(&mut self) -> &mut T;
}

AsRef很適合用于泛型代碼中,例如,下面的泛型函數(shù)接受各種類型,只要可以被轉(zhuǎn)換為&[u8]即可:

fn iter_bytes<T: AsRef<[u8]>>(arg: &T) {
    for i in arg.as_ref() {
        println!("{}", i);
    }
}

fn main() {
    let s = String::from("this is a string");
    let v = vec![1, 2, 3];
    let c = "hello";

    iter_bytes(&s);
    iter_bytes(&v);
    iter_bytes(&c);
}
Borrow / BorrowMut

Borrow、BorrowMut這兩個(gè)trait的設(shè)計(jì)和AsRefAsMut很類似:

pub trait Borrow<Borrowed: ?Sized> {
    fn borrow(&self) -> &Borrowed;
}

pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

但區(qū)別在于兩點(diǎn):

  • 標(biāo)準(zhǔn)庫為所有的T、&T&mut T默認(rèn)實(shí)現(xiàn)了BorrowBorrowMut,以Borrow為例:

impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T {
        self
    }
}

impl<T: ?Sized> Borrow<T> for &T {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<T: ?Sized> Borrow<T> for &mut T {
    fn borrow(&self) -> &T {
        &**self
    }
}
  • Borrow要求返回的類型,必須和原來的類型具備同樣的hash值。這是一個(gè)約定,如果違反了這個(gè)約定,那么把這個(gè)類型放到HashMap里時(shí)可能會(huì)出現(xiàn)問題。

From / Into

AsRefBorrow都是從&T&U的轉(zhuǎn)換,而From/Into是從TU的轉(zhuǎn)換:

pub trait From<T>: Sized {
    fn from(_: T) -> Self;
}
pub trait Into<T>: Sized {
    fn into(self) -> T;
}

由于FromInto是互逆的一組轉(zhuǎn)換,因此標(biāo)準(zhǔn)庫提供了這樣一個(gè)實(shí)現(xiàn):

impl<T, U> Into<U> for T
where
    U: From<T>,
{
    fn into(self) -> U {
        U::from(self)
    }
}

這段代碼的含義是:如果存在U: From<T>,則為類型T實(shí)現(xiàn)Into<U>。也就是說,我們只需為類型實(shí)現(xiàn)From即可,Into會(huì)自動(dòng)實(shí)現(xiàn)。標(biāo)準(zhǔn)庫中還有一組對(duì)應(yīng)的TryFromTryInto,他們是為了處理類型轉(zhuǎn)換過程中可能發(fā)生轉(zhuǎn)換錯(cuò)誤的情況,因此返回值是Result類型。

ToOwned

ToOwned提供一種更泛化的Clone的功能,Clone是從&T類型變量創(chuàng)造一個(gè)新的T類型變量,而ToOwned是從一個(gè)&T類型變量創(chuàng)造一個(gè)新的U類型變量,標(biāo)準(zhǔn)庫中也提供了ToOwned調(diào)用clone方法的默認(rèn)實(shí)現(xiàn):

pub trait ToOwned {
    type Owned: Borrow<Self>;

    fn to_owned(&self) -> Self::Owned;

    fn clone_into(&self, target: &mut Self::Owned) {
        *target = self.to_owned();
    }
}

impl<T> ToOwned for T
where
    T: Clone,
{
    type Owned = T;
    fn to_owned(&self) -> T {
        self.clone()
    }

    fn clone_into(&self, target: &mut T) {
        target.clone_from(self);
    }
}
ToString / FromStr

ToString提供了其他類型轉(zhuǎn)換為String類型的能力:

pub trait ToString {
    fn to_string(&self) -> String;
}

標(biāo)準(zhǔn)庫中為所有實(shí)現(xiàn)了Displaytrait的類型默認(rèn)實(shí)現(xiàn)了ToString,而Display可以通過derive實(shí)現(xiàn):

impl<T: fmt::Display + ?Sized> ToString for T {
    default fn to_string(&self) -> String {
        use fmt::Write;
        let mut buf = String::new();
        buf.write_fmt(format_args!("{}", self))
            .expect("a Display implementation returned an error unexpectedly");
        buf
    }
}

FromStr提供了從字符串切片向其他類型轉(zhuǎn)換的能力:

pub trait FromStr: Sized {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

IO

這里的IO指的是標(biāo)準(zhǔn)輸入輸出和文件輸入輸出。

標(biāo)準(zhǔn)輸入輸出

我們之前介紹過的println!宏可以方便地隨手輸出一些信息,但如果要對(duì)標(biāo)準(zhǔn)輸入輸出作更精細(xì)的控制,則需要調(diào)用std::io::stdin()函數(shù)和std::io::stdout()函數(shù)來獲取StdinStdout結(jié)構(gòu)體的實(shí)例。這兩個(gè)實(shí)例的簡(jiǎn)單用法如下:

use std::io::{self, Read};

fn main() -> io::Result<()> {
    let mut buffer = String::new();
    let mut stdin = io::stdin(); 
    stdin.read_to_string(&mut buffer)?;
    Ok(())
}

為了線程安全考慮,每次讀取操作都需要上鎖,這降低了效率。解決的方法是手動(dòng)調(diào)用lock()方法,但這又增添了使用標(biāo)準(zhǔn)輸入輸出的復(fù)雜度。

事實(shí)上,我們受學(xué)生時(shí)代做各種C語言大作業(yè)的影響,導(dǎo)致我們認(rèn)為標(biāo)準(zhǔn)輸入輸出是非常重要的功能,可我們細(xì)想一下,正兒八經(jīng)的命令行程序誰會(huì)用標(biāo)準(zhǔn)輸入來和用戶交互呢?一般都是通過兩種方式,一則是調(diào)用程序的時(shí)候指定參數(shù),另一則是通過文件讀取用戶配置。

文件輸入輸出

文件輸入輸出首先要解決路徑問題。Rust中的字符串類型是Stringstr,它們都是用utf-8進(jìn)行編碼的。但是,在具體的操作系統(tǒng)上并不是統(tǒng)一使用utf-8編碼,為了應(yīng)付這種情況,Rust中設(shè)計(jì)了OsStringOsStr,這兩種類型使用方法和Stringstr類似,并且它們之間也可以互相轉(zhuǎn)換。

Rust標(biāo)準(zhǔn)庫提供了std::path::PathBufstd::path::Path來處理路徑,PathBuf對(duì)內(nèi)部數(shù)據(jù)擁有所有權(quán),而Path只是借用,事實(shí)上,PathBuf內(nèi)部存儲(chǔ)了一個(gè)OsString,而Path則是存儲(chǔ)了Path

Rust的文件操作主要通過std::fs::File來完成,可以實(shí)現(xiàn)打開、創(chuàng)建、復(fù)制等文件操作。對(duì)于文件的讀寫,就要用到std::io模塊中的一些trait了,例如ReadWrite。File實(shí)現(xiàn)了這 兩個(gè)trait,因此擁有read等讀取文件的方法。

下面看一個(gè)例子來演示說明文件輸入輸出的方法:

use std::fs::File;
use std::io::{BufRead, BufReader, Read};

fn test_read_file() -> Result<(), std::io::Error> {
    let mut path = std::env::current_dir().unwrap();
    path.push("Cargo.toml");

    let mut file = File::open(&path)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;

    println!("{}", buffer);
    Ok(())
}

fn main() {
    match test_read_file() {
        Ok(_) => {}
        Err(e) => {
            println!("{}", e);
        }
    }
}

容器

和C++的STL類似,Rust的標(biāo)準(zhǔn)庫也給我們提供了一些比較常用的容器以及相關(guān)的迭代器,目前實(shí)現(xiàn)了的容器有:

容器描述
Vec可變長(zhǎng)數(shù)組,連續(xù)存儲(chǔ)
VecDeque雙向隊(duì)列,適用于從頭部和尾部插入刪除數(shù)據(jù)
LinkedList雙向鏈表,非連續(xù)存儲(chǔ)
HashMap基于Hash算法存儲(chǔ)一系列鍵值對(duì)
BTreeMap基于B樹存儲(chǔ)一系列鍵值對(duì)
HashSet相當(dāng)于沒有值的HashMap
BTreeSet相當(dāng)于沒有值的BTreeMap
BinaryHeap基于二叉堆實(shí)現(xiàn)的優(yōu)先級(jí)隊(duì)列

這里不詳細(xì)展開講,以后會(huì)對(duì)各個(gè)容器的用法和實(shí)現(xiàn)原理進(jìn)行深入探究。

迭代器

Rust中的迭代器是指實(shí)現(xiàn)了std::iter::Iterator這個(gè)trait的類型,其定義如下:

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    ...
}

它最主要的方法是next(),返回一個(gè)Option<Item>,迭代完成則返回None。實(shí)現(xiàn)了Iterator的類型可直接用于for循環(huán)。

迭代器擁有一個(gè)很重要的特性,就是它是可組合的,這有點(diǎn)類似于Java中的流式編程。Iterator中有很多方法,它們返回的類型也實(shí)現(xiàn)了Iterator,這意味著,我們調(diào)用這些方法可以從一個(gè)迭代器創(chuàng)造出一個(gè)新的迭代器,例如:

fn main() {
    let v = vec![1, 2, 3, 4, 5, 6, 7, 8];
    let mut iter = v
        .iter()
        .take(5)
        .filter(|&x| x % 2 == 0)
        .map(|&x| x * x)
        .enumerate();
    while let Some((i, v)) = iter.next() {
        println!("{}: {}", i, v);
    }
}

這段代碼的含義是:從v這個(gè)Vec的前五個(gè)元素中篩選元素,要求它必須是2的倍數(shù),并把該元素進(jìn)行平方,因此,最終的輸出結(jié)果是0: 41: 16。

運(yùn)算符重載

Rust支持自定義類型重載部分運(yùn)算符,只需該類型實(shí)現(xiàn)std::ops模塊下相應(yīng)的trait即可。以Add為例:

pub trait Add<Rhs = Self> {
    type Output;
    fn add(self, rhs: Rhs) -> Self::Output;
}

它具備一個(gè)泛型參數(shù)RHS和一個(gè)關(guān)聯(lián)類型Output。標(biāo)準(zhǔn)庫中早已為基本的數(shù)字類型實(shí)現(xiàn)了這個(gè)trait:

macro_rules! add_impl {
    ($($t:ty)*) => ($(
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Add for $t {
            type Output = $t;

            #[inline]
            #[rustc_inherit_overflow_checks]
            fn add(self, other: $t) -> $t { self + other }
        }

        forward_ref_binop! { impl Add, add for $t, $t }
    )*)
}

add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }

到此,相信大家對(duì)“Rust常用的標(biāo)準(zhǔn)庫工具有哪些”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI