Rust~String、str、str、String、Box<str> 或 Box<str>

Rust語言圣經中定義

str

Rust 語言類型大致分為兩種:基本類型和標準庫類型,前者由語言特性直接提供,后者在標準庫中定義

str 是唯一定義在 Rust 語言特性中的字符串,但也是幾乎不會用到的字符串類型
str 字符串是 DST 動態大小類型,編譯器無法在編譯期知道 str 類型的大小,只有到了運行期才能動態獲知
這對于強類型、強安全的 Rust 語言來說不可接受

let string: str = "banana";

創建一個 str 類型的字符串,編譯會報錯:

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] 是數組切片
str 是 String 和 &str 的底層數據類型

String

str 類型是硬編碼進可執行文件,無法被修改
String 是一個可增長、可改變且具有所有權的 UTF-8 編碼的字符串
Rust 提到字符串時,往往指的是 String 類型和 &str 字符串切片類型,這兩個類型都是 UTF-8 編碼

示例

在這里插入圖片描述
在這里插入圖片描述

其他

Rust 的標準庫還提供了其他類型的字符串,例如 OsString, OsStr, CsString 和 CsStr 等
這些名字都以 String 或者 Str 結尾,它們分別對應的是具有所有權和被借用的變量

具體區分

String

類型本質:String 是一個可變的、擁有所有權的字符串類型,存儲在堆上,并且可以動態增長
內存管理:由 Rust 的所有權系統管理,當 String 離開作用域時,其占用的內存會被自動釋放
使用場景:當需要對字符串進行修改(如追加、刪除字符)時使用

fn main() {let mut s = String::from("hello");s.push_str(", world!");println!("{}", s);
}

str

類型本質:str 是一個不可變的、無固定大小的字符串切片類型,通常被稱為 “字符串切片”。沒有所有權,只是對存儲在其他地方的字符串數據的引用
內存管理:由于 str 是無固定大小的類型,不能直接使用,通常以引用的形式 &str 出現
使用場景:用于表示一個字符串的一部分,如字符串的子串

&str

類型本質:&str 是對 str 類型的引用,是一個不可變的字符串切片。它指向一個連續的 UTF - 8 編碼的字節序列
內存管理:是一個借用類型,不擁有底層數據的所有權,只要借用的對象存在,&str 就有效
使用場景:當只需要讀取字符串內容而不需要修改它時,使用 &str 作為函數參數可以接受多種字符串類型(如 String 和字面量字符串)

fn print_string(s: &str) {println!("{}", s);
}fn main() {let s1 = String::from("hello");print_string(&s1);print_string("world");
}

&String

類型本質:&String 是對 String 類型的引用
內存管理:是一個借用類型,不擁有 String 的所有權,只要 String 對象存在,&String 就有效
使用場景:通常在已經有 String 類型的變量,而函數參數要求引用時使用

fn print_string_ref(s: &String) {println!("{}", s);
}fn main() {let s = String::from("hello");print_string_ref(&s);
}

Box<str>

類型本質:Box<str> 是將 str 類型裝箱到堆上的類型。它擁有底層 str 的所有權
內存管理:當 Box<str> 離開作用域時,底層的 str 數據會被自動釋放
使用場景:當需要在堆上存儲 str 數據,并且希望擁有其所有權時使用

fn main() {let s: Box<str> = "hello".into();println!("{}", s);
}

Box<&str>

類型本質:Box<&str> 不是一個常見用法,&str 本身是引用類型,將其裝箱沒意義。Box<&str> 會在堆上存儲一個 &str 引用
內存管理:Box<&str> 擁有這個引用的所有權,但引用指向的數據本身的生命周期需要單獨管理
使用場景:一般不建議使用,容易造成混淆

OsString 和 OsStr

類型本質:OsString 是一個擁有所有權的字符串類型,用于表示操作系統相關的字符串,如文件路徑。OsStr 是 OsString 的不可變視圖,類似于 str 是 String 的不可變視圖
內存管理:OsString 管理自己的內存,OsStr 是借用類型
使用場景:在處理與操作系統交互的字符串時使用,如文件系統操作

use std::ffi::OsString;
use std::path::PathBuf;fn main() {let os_string = OsString::from("example.txt");let path = PathBuf::from(os_string);println!("{:?}", path);
}

注意:OsString 和 String 的內存管理不一樣

CsString 和 CsStr

類型本質:CsString 和 CsStr 是 cstr_core crate 中的類型,用于處理以空字符結尾的 C 風格字符串。CsString 擁有字符串數據,CsStr 是不可變視圖
內存管理:CsString 管理自己的內存,CsStr 是借用類型
使用場景:在與 C 代碼進行交互時,需要處理 C 風格字符串時使用

use cstr_core::CStr;
use std::ffi::CString;fn main() {let c_string = CString::new("hello").unwrap();let c_str = c_string.as_c_str();println!("{:?}", c_str);
}

注意:CsString 和 String 的內存管理不一樣

如何查看字符串的大小

String

fn main() {// String 內部是以 UTF - 8 字節序列存儲// String 是 Rust 標準庫中用于表示可增長、擁有所有權的 UTF - 8 編碼字符串的類型let s = String::from("Hello, 世界");// 獲取字節長度let byte_length = s.len();// 13println!("Byte length: {}", byte_length);// 獲取字符數量let char_count = s.chars().count();// 9println!("Character count: {}", char_count);
}

CsString

use cstr_core::CString;fn main() {let cs_string = CString::new("Hello, C-style").expect("Failed to create CString");// 獲取不包含空字符的字節長度let byte_length_without_nul = cs_string.as_c_str().to_bytes().len();// 14println!("Byte length without null terminator: {}", byte_length_without_nul);// 獲取包含空字符的字節長度let byte_length_with_nul = cs_string.as_c_str().to_bytes_with_nul().len();// 15println!("Byte length with null terminator: {}", byte_length_with_nul);
}

OsString

可以將 OsString 轉換為 OsStr,然后根據操作系統的編碼方式將其轉換為 &str 或字節切片來獲取長度

use std::ffi::OsString;fn main() {let os_string = OsString::from("Hello, OS");// 嘗試將 OsString 轉換為 &str 并獲取長度if let Some(s) = os_string.to_str() {let byte_length = s.len();// 9println!("Byte length: {}", byte_length);}
}

在上述代碼中,os_string.to_str() 嘗試將 OsString 轉換為 &str,如果轉換成功,則可以使用 len() 方法獲取其字節長度。需要注意的是,to_str() 可能會失敗,因為 OsString 可能包含非 UTF - 8 編碼的數據。如果需要處理非 UTF - 8 數據,可以使用 os_string.into_vec() 方法將其轉換為字節向量,然后獲取向量的長度。
綜上所述,不同類型的字符串獲取長度的方法有所不同,需要根據具體類型和需求選擇合適的方法。

std::ffi::OsString的os_string.to_str()

pub fn to_str(&self) -> Option<&str>

&OsString轉為Option<&str>

pub trait Deref {type Target: ?Sized;// Required methodfn deref(&self) -> &Self::Target;
}// 
impl ops::Deref for OsString {type Target = OsStr;#[inline]fn deref(&self) -> &OsStr {&self[..]}
}

to_str() 是 OsStr 類型的一個方法,OsString 可以通過自動解引用轉換為 OsStr 來調用這個方法。
to_str() 方法的作用是嘗試將 OsStr 轉換為 &str
它的實現原理是檢查 OsStr 內部存儲的字節序列是否是有效的 UTF - 8 編碼。如果是有效的 UTF - 8 編碼,就返回一個 Some(&str);如果不是有效的 UTF - 8 編碼,則返回 None

Deref 機制主要用于在需要某個類型的引用時,自動將一個類型的引用轉換為另一個類型的引用。
String 實現了 Deref<Target = str>,意味著當有一個 &String 類型的變量時,Rust 會自動將其轉換為 &str,以便可以調用 str 類型的方法。

os_string.to_str() 并不是依賴 Deref 來完成從 OsString 到 &str 的轉換。它是通過檢查 OsStr 內部字節序列的 UTF - 8 有效性來進行轉換的。

自動解引用

以 OsString 轉換 OsStr 為例
在 Rust 中,OsString 可以自動解引用轉換為 OsStr,這種轉換主要發生在以下幾種場景:

調用 OsStr 方法時

當調用一個 OsStr 類型的方法,而實際操作的是 OsString 實例時,Rust 會自動進行解引用轉換。
這是因為 OsString 實現了 Deref<Target = OsStr> 特征,該特征允許 Rust 在需要 OsStr 引用的地方使用 OsString 引用

use std::ffi::OsString;fn main() {let os_string = OsString::from("example.txt");// 調用 OsStr 的 to_str 方法,這里自動將 OsString 轉換為 OsStrif let Some(s) = os_string.to_str() {println!("Converted to &str: {}", s);}
}

在上述代碼中,os_string 是 OsString 類型,但 to_str 是 OsStr 類型的方法

作為函數參數傳遞時

當一個函數的參數類型是 &OsStr,而傳遞的是 &OsString 時,Rust 會自動進行解引用轉換。

use std::ffi::{OsStr, OsString};fn print_os_str(os_str: &OsStr) {if let Some(s) = os_str.to_str() {println!("{}", s);}
}fn main() {let os_string = OsString::from("test.txt");// 自動將 &OsString 轉換為 &OsStr 傳遞給函數print_os_str(&os_string);
}

賦值給 &OsStr 類型變量時

當將一個 &OsString 賦值給一個 &OsStrc類型的變量時,也會發生自動解引用轉換。

use std::ffi::OsString;fn main() {let os_string = OsString::from("file.txt");// 自動將 &OsString 轉換為 &OsStrlet os_str: &OsStr = &os_string;if let Some(s) = os_str.to_str() {println!("{}", s);}
}

這里,&os_string&OsString 類型,而 os_str 是 &OsStr 類型,Rust 會自動完成轉換。

既然可以通過Defef自動轉換,那還要as_os_str干嘛

pub fn as_os_str(&self) -> &OsStr

顯式表達意圖

代碼的可讀性和可維護性在軟件開發中至關重要。使用 as_os_str 方法可以更清晰地表達想要將 OsString 轉換為 &OsStr 的意圖。相比自動解引用,顯式調用方法能讓閱讀代碼的人一眼就明白正在進行類型轉換操作。

use std::ffi::OsString;fn main() {let os_string = OsString::from("example.txt");// 顯式轉換,意圖清晰let os_str = os_string.as_os_str(); if let Some(s) = os_str.to_str() {println!("{}", s);}
}

避免潛在的混淆

在某些復雜的代碼場景中,自動解引用可能會導致代碼的行為變得難以理解。自動解引用是 Rust 編譯器在背后自動完成的,當代碼中有多個類型實現了 Deref 特征時,可能會引發混淆。使用 as_os_str 可以避免這種潛在的混淆,讓代碼的行為更加明確。

與其他類型轉換保持一致性

在 Rust 標準庫中,很多類型都提供了顯式的類型轉換方法,比如 String 有 as_str 方法用于轉換為 &strVec<T> 有 as_slice 方法用于轉換為 &[T]。OsString 的 as_os_str 方法與這些設計保持一致,使得代碼的風格更加統一。

代碼審查和調試

在代碼審查過程中,顯式的類型轉換方法更容易被審查人員識別和理解。同時,在調試代碼時,顯式調用方法可以讓調試者更清楚地看到類型轉換的位置和過程,有助于快速定位問題。

總結

盡管 Deref 自動轉換提供了便利,但 as_os_str 方法通過顯式表達意圖、避免混淆、保持一致性以及方便代碼審查和調試等方面,為代碼的質量和可維護性提供了保障。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/896806.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/896806.shtml
英文地址,請注明出處:http://en.pswp.cn/news/896806.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大數據SQL調優專題——底層調優

引入 上一篇我們提到了調優的常見切入點&#xff0c;核心就是通過數據產出情況發現問題&#xff0c;借助監控等手段收集信息排查瓶頸在哪&#xff0c;最后結合業務理解&#xff0c;等價重寫思路去解決問題。 在實際工作場景中&#xff0c;去保證數據鏈路產出SLA的時候&#x…

Hue 編譯異常:ImportError: cannot import name ‘six‘ from ‘urllib3.packages‘

個人博客地址&#xff1a;Hue 編譯異常&#xff1a;ImportError: cannot import name six from urllib3.packages | 一張假鈔的真實世界 在編譯Hue的時候出現錯誤信息如下&#xff1a; Running /home/zhangjc/ysten/git/ysten-hue/build/env/bin/hue makemigrations --noinpu…

計算機網絡——詳解TCP三握四揮

文章目錄 前言一、三次握手1.1 三次握手流程1.2 tcp為什么需要三次握手建立連接&#xff1f; 二、四次揮手2.1 四次揮手流程2.2 為什么是四次&#xff0c;不是三次&#xff1f;2.3 為什么要等待2msl&#xff1f;2.4 TCP的保活計時器 前言 TCP和UDP是計算機網絡結構中運輸層的兩…

# C# 中堆(Heap)與棧(Stack)的區別

在 C# 中&#xff0c;堆和棧是兩種不同的內存分配機制&#xff0c;它們在存儲位置、生命周期、性能和用途上存在顯著差異。理解堆和棧的區別對于優化代碼性能和內存管理至關重要。 1. 棧&#xff08;Stack&#xff09; 1.1 定義 棧是一種后進先出&#xff08;LIFO&#xff0…

如何把圖片或者圖片地址存到 MySQL 數據庫中以及如何將這些圖片數據通過 JSP 顯示在網頁中

如何優雅地管理圖片&#xff1a;從MySQL數據庫存儲到JSP展示的全流程解析 在互聯網時代&#xff0c;一張引人入勝的圖片往往能為網站帶來巨大的流量。而作為開發者的我們&#xff0c;如何高效地管理和展示這些圖片資源則成為了一項重要的技術挑戰。今天&#xff0c;我們就一起…

「拼好幀」小黃鴨 Lossless Scaling 軟件介紹與下載

「拼好幀」小黃鴨 Lossless Scaling 軟件介紹與下載 在游戲和視頻播放時&#xff0c;你是否遇到過分辨率不匹配、畫質模糊的問題&#xff1f;今天給大家介紹一款神器——Lossless Scaling&#xff08;拼好幀&#xff09;&#xff0c;也被玩家們親切地稱為“小黃鴨”&#xff0…

科普|無人機專業術語

文章目錄 前言一、飛控二、電調三、通道四、2S、3S、4S電池五、電池后面C是什么意思?六、電機的型號七、什么是電機的KV值?八、螺旋槳的型號九、電機與螺旋槳的搭配 前言 無人機飛控系統控制飛行姿態&#xff0c;電調控制電機轉速&#xff0c;遙控器通道控制飛行動作。電池C…

和鯨科技攜手四川氣象,以 AI 的力量賦能四川氣象一體化平臺建設

氣象領域與農業、能源、交通、環境科學等國計民生關鍵領域緊密相連&#xff0c;發揮著不可替代的重要作用。人工智能技術的迅猛發展&#xff0c;為氣象領域突破困境帶來了新的契機。AI 技術能夠深度挖掘氣象大數據中蘊含的復雜信息&#xff0c;助力人類更精準地把握自然規律&am…

Linux mount命令

Linux mount命令是經常會使用到的命令&#xff0c;它用于掛載Linux系統外的文件。 一、掛載功能介紹 掛載方法&#xff1a;mount DECE MOUNT_POINT 命令使用格式&#xff1a;mount [-fnrsvw] [-t vfstype] [-o options] device dir device&#xff1a;指明要掛載的設備&…

《Operating System Concepts》閱讀筆記:p177-p178

《Operating System Concepts》學習第 18 天&#xff0c;p177-p178 總結&#xff0c;總計 2 頁。 一、技術總結 1.implicit thread A programming model that transfers the creation and management of threading from application developers to compilers and run-time l…

Redis緩存一致性難題:如何讓數據庫和緩存不“打架”?

標題&#xff1a;Redis緩存一致性難題&#xff1a;如何讓數據庫和緩存不“打架”&#xff1f;&#xff08;附程序員脫發指南&#xff09; 導言&#xff1a;當數據庫和緩存成了“異地戀” 想象一下&#xff1a;你剛在美團下單了一份麻辣小龍蝦&#xff0c;付款后刷新頁面&#…

委托者模式(掌握設計模式的核心之一)

目錄 問題&#xff1a; 舉例&#xff1a; 總結&#xff1a;核心就是利用Java中的多態來完成注入。 問題&#xff1a; 今天刷面經&#xff0c;刷到裝飾者模式&#xff0c;又進階的發現委托者模式&#xff0c;發現還是不理解&#xff0c;特此記錄。 舉例&#xff1a; ?老板?…

[密碼學實戰]Java實現SM4加解密(ecb,cbc)及工具驗證

前言 在現代信息安全領域,數據加密技術是保障數據安全的核心手段之一。SM4作為中國國家密碼管理局發布的對稱加密算法,因其高效性和安全性,廣泛應用于金融、政務、通信等領域。本文將詳細介紹如何使用Java實現SM4的加解密操作,并深入探討SM4的幾種常見加密模式及其原理。 …

動態規劃刷題

文章目錄 動態規劃三步問題題目解析代碼 動態規劃 1. 狀態表示&#xff1a;dp[i]&#xff0c;表示dp表中i下標位置的值 2. 狀態轉移方程&#xff1a;以i位置位置的狀態&#xff0c;最近的一步來劃分問題&#xff0c;比如可以將狀態拆分成前狀態來表示現狀態&#xff0c;dp[i] …

Vue 3 搭建前端模板并集成 Ant Design Vue(2025)

目錄 一、環境安裝 二、創建項目 三、前端工程化配置 四、引入組件庫 五、選擇 API 風格 1、選項式 API (Options API)? 2、組合式 API (Composition API)? 六、頁面信息修改 七、通用布局選擇 1、基礎布局結構 2、全局底部欄 3、動態替換內容 4、全局頂部欄 …

C++雜記——RTTI

run-time type information or run-time type identification (RTTI) RTTI&#xff08;Runtime Type Information&#xff09;是C中的一個特性&#xff0c;允許程序在運行時獲取類型信息。它主要用于多態&#xff08;尤其是基于類的多態&#xff09;時&#xff0c;幫助判斷對象…

【Mac】git使用再學習

目錄 前言 如何使用github建立自己的代碼庫 第一步&#xff1a;建立本地git與遠程github的聯系 生成密鑰 將密鑰加入github 第二步&#xff1a;創建github倉庫并clone到本地 第三步&#xff1a;上傳文件 常見的git命令 git commit git branch git merge/git rebase …

六十天前端強化訓練之第七天CSS預處理器(Sass)案例:變量與嵌套系統詳解

歡迎來到編程星辰海的博客講解 目錄 一、知識講解&#xff08;3000字&#xff09; 1. Sass基礎概念 2. 變量系統 2.1 變量定義 2.2 數據類型 2.3 作用域優先級 2.4 變量實踐場景 3. 嵌套系統 3.1 選擇器嵌套 3.2 屬性嵌套 3.3 嵌套規則 二、核心代碼示例 完整SCSS…

Docker和K8S中pod、services、container的介紹和關系

在容器化技術中&#xff0c;Docker、Kubernetes&#xff08;K8S&#xff09;、Pod、Service 和 Container 是核心概念&#xff0c;理解它們的關系對構建和管理現代應用至關重要。以下是詳細的分步解釋&#xff1a; 1. 核心概念定義 (1) Container&#xff08;容器&#xff09;…

DeepSeek掘金——DeepSeek R1驅動的PDF機器人

DeepSeek掘金——DeepSeek R1驅動的PDF機器人 本指南將引導你使用DeepSeek R1 + RAG構建一個功能性的PDF聊天機器人。逐步學習如何增強AI檢索能力,并創建一個能夠高效處理和響應文檔查詢的智能聊天機器人。 本指南將引導你使用DeepSeek R1 + RAG構建一個功能性的PDF聊天機器人…