Rust 數據結構:String

Rust 數據結構:String

  • Rust 數據結構:String
    • 什么是字符串?
    • 創建新字符串
    • 更新字符串
      • 將 push_str 和 push 附加到 String 對象后
      • 使用 + 運算符和 format! 宏
    • 索引到字符串
      • 字符串在內存中的表示
      • 字節、標量值和字形簇
    • 分割字符串
    • 遍歷字符串的方法

Rust 數據結構:String

在本文中,我們將討論每種集合類型都具有的 String 操作,例如創建、更新和讀取。我們還將討論 String 與其他集合的不同之處,即由于人和計算機解釋 String 數據的方式不同,對 String 進行索引變得復雜。

什么是字符串?

Rust 在核心語言中只有一種字符串類型,它是字符串切片 str,通常以它的借用形式 &str 出現。字符串切片是對存儲在其他地方的一些 UTF-8 編碼字符串數據的引用。例如,字符串字面值存儲在程序的二進制文件中,因此是字符串切片。

String 類型是由 Rust 的標準庫提供的,而不是編碼到核心語言中,它是一個可增長的、可變的、擁有的、UTF-8 編碼的字符串類型。

當在 Rust 使用“字符串”時,它們可能指的是 String 或 String slice &str 類型,而不僅僅是其中一種類型。雖然本文主要是關于 String 的,但這兩種類型在 Rust 的標準庫中都大量使用,并且 String 和 String 切片都是 UTF-8 編碼的。

創建新字符串

String 實際上是作為字節向量的包裝器實現的,帶有一些額外的保證、限制和功能,所以在使用上很多和 vector 類似。

let mut s = String::new();

這一行創建了一個新的空字符串 s,然后我們可以將數據加載到其中。

通常,我們會有一些初始數據,我們想用這些數據開始字符串。為此,我們使用 to_string 方法,該方法可用于任何實現 Display trait 的類型,就像字符串字面量一樣。

    let data = "initial contents";let s = data.to_string();// The method also works on a literal directly:let s = "initial contents".to_string();

還可以使用 String::from 函數從字符串字面值創建 String。

let s = String::from("initial contents");

更新字符串

String 的大小可以增長,其內容可以改變。

將 push_str 和 push 附加到 String 對象后

push_str 方法接受一個字符串切片,并且不獲取參數的所有權。

    let mut s = String::from("foo");s.push_str("bar");

push 方法接受單個字符作為參數,并將其添加到 String 中。

    let mut s = String::from("lo");s.push('l');

使用 + 運算符和 format! 宏

+ 操作符可以組合兩個現有字符串。

    let s1 = String::from("Hello, ");let s2 = String::from("world!");let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used

s1 在相加之后不再有效的原因,以及我們使用 s2 引用的原因,與使用 + 操作符時調用的方法的簽名有關。+ 操作符使用 add 方法,其簽名看起來像這樣:

fn add(self, s: &str) -> String {

首先,s2 有一個 &,這意味著我們將第二個字符串的引用添加到第一個字符串。

我們能夠在 add 調用中使用&s2(String 類型)的原因是編譯器可以將 &String 實參強制轉換為 &str。當我們調用 add 方法時,Rust 使用了一個強制轉換,它將 &s2 轉換為 &s2[…]。因為 add 沒有獲得 s 形參的所有權,所以在這個操作之后 s2 仍然是一個有效的 String。

其次,我們可以在簽名中看到 add 取得了 self 的所有權,因為 self 沒有 &。這意味著 s1 將被移動到 add 調用中,并且在此之后將不再有效。

綜上,s3 = s1 + &s2; 看起來它將復制兩個字符串并創建一個新字符串,這個語句實際上獲取 s1 的所有權,附加 s2 內容的副本,然后返回結果的所有權。

如果需要連接多個字符串,則 + 操作符的行為會變得笨拙:

    let s1 = String::from("tic");let s2 = String::from("tac");let s3 = String::from("toe");let s = s1 + "-" + &s2 + "-" + &s3;

對于以更復雜的方式組合字符串,我們可以使用 format! 宏:

    let s1 = String::from("tic");let s2 = String::from("tac");let s3 = String::from("toe");let s = format!("{s1}-{s2}-{s3}");

format! 宏返回一個包含內容的 String。format! 宏使用引用,因此此調用不會獲得其任何參數的所有權。

索引到字符串

在許多其他編程語言中,通過索引引用字符串中的單個字符是一種有效且常見的操作。但是,如果嘗試在 Rust 中使用索引語法訪問 String 的某些部分,則會得到一個錯誤。

    let s1 = String::from("hi");let h = s1[0];

報錯:error[E0277]: the type `str` cannot be indexed by `{integer}`

這個要從 Rust 如何在內存中 存儲字符串開始講起。

字符串在內存中的表示

String是Vec<u8>的包裝器。

考慮以下兩個字符串:

let s1 = String::from("Hola");
let s2 = String::from("Здравствуйте");

s1 的長度是 4 字節。當用 UTF-8 編碼時,這些字母中的每個都占 1 字節。然而,s2 的長度不是 12 字節,而是 24 字節。因為該字符串中的每個 Unicode 標量值需要 2 字節的存儲空間。

來看一下錯誤代碼:

let hello = "Здравствуйте";
let answer = &hello[0];

當用 UTF-8 編碼時,З 的第一個字節是 208,第二個字節是 151,所以看起來答案實際上應該是 208,但是 208 本身并不是一個有效的字符。為了避免返回意外值并導致可能無法立即發現的錯誤,Rust 根本不編譯此代碼。

字節、標量值和字形簇

關于 UTF-8 的另一點是,從 Rust 的角度來看,實際上有三種相關的方式來看待字符串:字節、標量值和字形簇(最接近我們稱之為字母的東西)。

如果我們看看寫在 Devanagari 腳本中的印地語單詞 “??????”,它被存儲為 u8 值的向量,看起來像這樣:

[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135]

這是 18 個字節,這就是計算機最終存儲這些數據的方式。如果我們把它們看作 Unicode 標量值,也就是 Rust 的 char 類型,這些字節看起來是這樣的:

['?', '?', '?', '?', '?', '?']

Rust 提供了不同的方式來解釋計算機存儲的原始字符串數據,這樣每個程序都可以選擇它需要的解釋,而不管這些數據是什么人類語言。

Rust 不允許我們索引 String 以獲取字符的最后一個原因是,索引操作總是需要常數時間(O(1))。但是不能保證 String 的性能,因為 Rust 必須從頭到尾遍歷內容,以確定有多少個有效字符。

分割字符串

對字符串進行索引通常不是一個好主意,與其用 [] 索引單個數字,不如用 [] 索引一個范圍來創建包含特定字節的字符串切片。

let hello = "Здравствуйте";let s = &hello[0..4];

這里,s 將是一個 &str,它包含字符串的前 4 個字節。前面,我們提到每個字符都是兩個字節,這意味著 s 將是 “Зд”。

如果我們嘗試用 &hello[0…1], Rust 會在運行時報錯,就像在 vector 中訪問無效索引一樣。

遍歷字符串的方法

對字符串片段進行操作的最佳方法是明確說明是需要字符還是字節。對于單個 Unicode 標量值,使用 chars 方法。在 “Зд” 上調用 chars,分離并返回兩個 char 類型的值,再遍歷。

for c in "Зд".chars() {println!("{c}");
}

程序輸出:

З
д

或者,bytes 方法返回每個原始字節。

for b in "Зд".bytes() {println!("{b}");
}

程序輸出:

208
151
208
180

一定要記住,有效的 Unicode 標量值可能由多個字節組成。

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

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

相關文章

Java卡與SSE技術融合實現企業級安全實時通訊

簡介 在數字化轉型浪潮中,安全與實時數據傳輸已成為金融、物聯網等高安全性領域的核心需求。本文將深入剖析東信和平的Java卡權限分級控制技術與浪潮云基于SSE的大模型數據推送技術,探索如何將這兩項創新技術進行融合,構建企業級安全實時通訊系統。通過從零到一的開發步驟,…

繼MCP、A2A之上的“AG-UI”協議橫空出世,人機交互邁入新紀元

第一章&#xff1a;AI交互的進化與挑戰 1.1 從命令行到智能交互 人工智能的發展歷程中&#xff0c;人機交互的方式經歷了多次變革。早期的AI系統依賴命令行輸入&#xff0c;用戶需通過特定指令與機器溝通。隨著自然語言處理技術的進步&#xff0c;語音助手和聊天機器人逐漸普…

MySQL刷題相關簡單語法集合

去重 distinct 關鍵字 eg. &#xff1a;select distinct university from user_profile 返回行數限制&#xff1a; limit關鍵字 eg. &#xff1a;select device_id from user_profile limit 2 返回列重命名&#xff1a;as 關鍵字 eg.&#xff1a;select device_id as user_in…

Kubernetes MCP服務器(K8s MCP):如何使用?

#作者&#xff1a;曹付江 文章目錄 1、什么是 Kubernetes MCP 服務器&#xff1f;1.1、K8s MCP 服務器 2、開始前的準備工作2.1. Kubernetes集群2.2. 安裝并運行 kubectl2.3. Node.js 和 Bun2.4. &#xff08;可選&#xff09;Helm v3 3、如何設置 K8s MCP 服務器3.1. 克隆存儲…

計算機網絡-HTTP與HTTPS

文章目錄 計算機網絡網絡模型網絡OSITCP/IP 應用層常用協議HTTP報文HTTP狀態碼HTTP請求類型HTTP握手過程HTTP連接HTTP斷點續傳HTTPSHTTPS握手過程 計算機網絡 網絡模型 為了解決多種設備能夠通過網絡相互通信&#xff0c;解決網絡互聯兼容性問題。 網絡模型是計算機網絡中用于…

Springboot 跨域攔截器配置說明

錯誤代碼 跨域設置 Configuration public class WebConfig implements WebMvcConfigurer {/*** cors 跨域配置*/Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedMethods("GET", "HEAD", &qu…

受不了github的網絡限制了,我開源了一個圖床工具 gitee-spring-boot-starter

嗨嗨嗨~ 我老馬又又來了&#xff01;&#xff01;&#xff01;上次寫了一篇我開源了一款阿里云OSS的spring-boot-starter&#xff0c;然后買的資源包到期了&#xff0c;后面又想白&#xff08;開&#xff09;嫖&#xff08;源&#xff09;的路子&#xff0c;首先想到了使用gith…

基于labview的聲音采集、存儲、處理

程序1&#xff1a;基于聲卡的數據采集 程序2&#xff1a;基于聲卡的雙聲道模擬輸出 程序3&#xff1a;聲音信號的采集與存儲 程序4&#xff1a;聲音信號的功率譜分析 程序5&#xff1a;基于labview的DTMF

第一次經歷項目上線

這幾天沒寫csdn&#xff0c;因為忙著項目上線的問題&#xff0c;我這階段改了非常多的前端bug哈哈哈哈&#xff0c;說幾個比較好的bug思想&#xff01; 這個頁面算是我遇到的比較大的bug&#xff0c;因為我一開始的邏輯都寫好了&#xff0c;詢價就是在點擊快遞公司彈出彈框的時…

基于EFISH-SCB-RK3576/SAIL-RK3576的消防機器人控制器技術方案?

&#xff08;國產化替代J1900的應急救援智能化解決方案&#xff09; 一、硬件架構設計? ?極端環境防護系統? ?防爆耐高溫設計?&#xff1a; 采用陶瓷纖維復合裝甲&#xff08;耐溫1200℃持續1小時&#xff09;&#xff0c;通過GB 26784-2023消防設備防爆認證IP68防護等級…

企業開發工具git的使用:從入門到高效團隊協作

前言&#xff1a;本文介紹了Git的安裝、本地倉庫的創建與配置&#xff0c;以及工作區、暫存區和版本庫的區分。詳細講解了版本回退、撤銷修改等操作&#xff0c;并深入探討了分支管理&#xff0c;包括分支的創建、切換、合并、刪除及沖突解決。此外&#xff0c;還介紹了遠程操作…

Java反射機制詳解:原理、應用與實戰

一、反射機制概述 Java反射(Reflection)是Java語言的一個強大特性&#xff0c;它允許程序在運行時(Runtime)獲取類的信息并操作類或對象的屬性、方法等。反射機制打破了Java的封裝性&#xff0c;但也提供了極大的靈活性。 反射的核心思想&#xff1a;在運行時而非編譯時動態獲…

成功案例丨從草圖到鞍座:用先進的發泡成型仿真技術變革鞍座制造

案例簡介 在鞍座制造中&#xff0c;聚氨酯泡沫成型工藝是關鍵環節&#xff0c;傳統依賴實驗測試的方法耗時且成本高昂。為解決這一問題&#xff0c;意大利自行車鞍座制造商 Selle Royal與Altair合作&#xff0c;采用Altair Inspire PolyFoam軟件進行發泡成型仿真。 該工具幫助團…

隧道結構安全在線監測系統解決方案

一、方案背景 隧道是地下隱蔽工程&#xff0c;會受到潛在、無法預知的地質因素影響。隨著我國公路交通建設的發展&#xff0c;隧道占新建公路里程的比例越來越大。隧道屬于線狀工程&#xff0c;有的規模較大&#xff0c;可長達幾公里或數十公里&#xff0c;往往穿越許多不同環境…

選錯方向太致命,華為HCIE數通和云計算到底怎么選?

現在搞HCIE的兄弟越來越多了&#xff0c;但“數通和云計算&#xff0c;到底考哪個&#xff1f;”這問題&#xff0c;依舊讓不少人頭疼。 一個是華為認證的老牌王牌專業——HCIE數通&#xff0c;穩、系統、崗位多&#xff1b; 一個是新趨勢方向&#xff0c;貼合云原生、數字化…

相機基礎常識

相機基礎常識 相機中顏色濾鏡的作用&#x1f3a8; 1. **捕捉彩色圖像**? 最常見的顏色濾鏡陣列是 **拜耳濾鏡&#xff08;Bayer Filter&#xff09;**&#xff1a; &#x1f50d; 2. **實現特定的圖像效果或分析功能**? 常見的濾鏡類型包括&#xff1a; &#x1f6e0;? 3. *…

paddle ocr本地化部署進行文字識別

一、Paddle 簡介 1. 基本概念 Paddle&#xff08;全稱 PaddlePaddle&#xff0c;飛槳&#xff09;是百度開發的 開源深度學習平臺&#xff0c;也是中國首個自主研發、功能豐富、技術領先的工業級深度學習平臺。它覆蓋了深度學習從數據準備、模型訓練、模型部署到預測的全流程…

開源AI大模型等“神秘組合”,如何顛覆零售業數字化轉型?

基于開源AI大模型、AI智能名片與S2B2C商城小程序源碼的零售行業數字化轉型新路徑研究 摘要&#xff1a;在業界將企業數字化轉型劃分為管理數字化、工業數字化和營銷數字化三大部分的背景下&#xff0c;國內大型制造企業在ERP與工業4.0洗禮下正邁向智能型發展道路。而零售行業面…

uniapp+vite+cli模板引入tailwindcss

目前vitecli方式用的都是官方提供的模板&#xff0c;vite版本還是4.14版本&#xff0c;較舊&#xff0c;而tailwindcss已經有了4版本&#xff0c;實際發現引入最新版會報錯&#xff0c;因而繼續使用3.3.5版本 pnpm install tailwindcss3.3.5 uni-helper/vite-plugin-uni-tail…

Golang中的runtime.LockOSThread 和 runtime.UnlockOSThread

在runtime中有runtime.LockOSThread 和 runtime.UnlockOSThread 兩個函數&#xff0c;這兩個函數有什么作用呢&#xff1f;我們看一下標準庫中對它們的解釋。 runtime.LockOSThread // LockOSThread wires the calling goroutine to its current operating system thread. // T…