一文弄懂Rust之切片
概述
在Rust中,切片是一種非常重要的引用類型。它允許你安全地引用一段連續(xù)內(nèi)存中的數(shù)據(jù),而不需要擁有這些數(shù)據(jù)的所有權(quán)。切片不包含分配的內(nèi)存空間,它僅僅是一個(gè)指向數(shù)據(jù)開始位置和長(zhǎng)度的數(shù)據(jù)結(jié)構(gòu)。切片是對(duì)數(shù)組的一個(gè)連續(xù)引用,它提供了一種方便、高效的方式來操作數(shù)組的一部分。切片本身并不擁有數(shù)據(jù),它只是原始數(shù)組的一個(gè)視圖,因此創(chuàng)建切片通常是一個(gè)低開銷的操作。
切片的聲明
在Rust中,切片的聲明格式如下。
let slice_name: [T; n] = &array[start..end];
下面,我們?cè)敿?xì)介紹切片聲明中的各個(gè)元素。
slice_name:切片變量取的名字。
[T; n]:是一個(gè)泛型,表示一個(gè)包含n個(gè)類型為T的元素的切片。但在實(shí)際聲明中,通常不需要指定n,因?yàn)镽ust會(huì)根據(jù)初始化的數(shù)據(jù)自動(dòng)推斷出長(zhǎng)度。
&array[start..end]:創(chuàng)建一個(gè)從array中的start索引到end索引(但不包含 end 索引)的切片。start和end是范圍操作符..的參數(shù),用于定義切片的開始位置和結(jié)束位置(但不包括結(jié)束位置)。注意:start索引可以不寫,不寫時(shí)默認(rèn)為0;end索引也可以不寫,不寫時(shí)默認(rèn)為array的最后一個(gè)元素的索引。
在下面的示例代碼中,我們使用數(shù)組的切片操作創(chuàng)建了slice切片,Rust會(huì)自動(dòng)推斷出slice切片的類型為:&[i32]。
fn main() { let array = [1, 2, 3, 4, 5]; // 創(chuàng)建一個(gè)從索引1到索引4(不包含4)的切片 let slice = &array[1..4]; assert_eq!(slice, &[2, 3, 4]); }
如果我們要聲明一個(gè)可變切片,可以使用mut關(guān)鍵字。在下面的示例代碼中,&mut表示對(duì)原始數(shù)組的一個(gè)可變引用,這意味著你可以通過這個(gè)切片修改原始數(shù)組的內(nèi)容。
fn main() { let mut array = [1, 2, 3, 4, 5]; // 可變切片 let mutable_slice = &mut array[1..4]; // 輸出:[2, 3, 4] println!("{:?}", mutable_slice); }
如果我們要聲明一個(gè)空的切片,可以使用空數(shù)組字面量來初始化。在下面的示例代碼中,empty_slice是一個(gè)空的i32類型切片。注意:我們?cè)谶@里顯式指定了切片的類型,因?yàn)榭涨衅旧聿话銐虻男畔碜詣?dòng)推斷類型。
fn main() { let empty_slice: &[i32] = &[]; // 輸出:[] println!("{:?}", empty_slice); }
切片的使用
1、獲取切片的長(zhǎng)度,可以使用len()方法。
fn main() { let text = "Hello, CSDN"; let word = &text[0..5]; let len: usize = word.len(); // 輸出: 5 println!("{}", len); }
2、切片可以通過索引來訪問其內(nèi)部元素。切片的索引遵循與數(shù)組相同的規(guī)則:從0開始,并且是基于半開區(qū)間[start, end)的原則,即:包含起始索引,但不包含結(jié)束索引。
fn main() { let numbers = [1, 2, 3, 4, 5]; let slice: &[i32] = &numbers[2..]; // 輸出:3 println!("{}", slice[0]); let mut mut_numbers = [1, 2, 3, 4, 5]; let mut_slice: &mut [i32] = &mut mut_numbers[1..]; // 修改切片中的元素 mut_slice[0] *= 10; // 原始數(shù)組會(huì)被修改,輸出:20 println!("{}", mut_numbers[1]); }
注意:索引操作不會(huì)進(jìn)行越界檢查,如果嘗試訪問超出切片范圍的索引,將導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。為了安全地訪問切片元素,可以使用get()方法。
fn main() { let numbers = [1, 2, 3, 4, 5]; let slice: &[i32] = &numbers[2..]; // 安全訪問切片元素 if let Some(value) = slice.get(1) { // 輸出:element is: 4 println!("element is: {}", value); } else { println!("out of bounds"); } }
3、切片可以通過迭代器來進(jìn)行遍歷。我們可以使用for循環(huán)配合.iter()方法來迭代不可變切片中的元素,或者使用.iter_mut()方法來迭代可變切片中的元素。
fn main() { let numbers = [1, 2, 3, 4, 5]; let slice: &[i32] = &numbers[2..]; // 輸出:3 4 5 for number in slice.iter() { println!("{}", number); } let mut mut_numbers = [1, 2, 3, 4, 5]; let mut_slice: &mut [i32] = &mut mut_numbers[..]; // 修改切片中的元素 for number in mut_slice.iter_mut() { *number *= 10; } // 輸出:[10, 20, 30, 40, 50] println!("{:?}", mut_numbers); }
4、字符串切片(&str)可以通過chars()方法來迭代其中的Unicode字符。這是因?yàn)椋篟ust中的字符串是UTF-8編碼的,而一個(gè)Unicode字符可能由1到4個(gè)字節(jié)組成。chars()方法會(huì)返回一個(gè)實(shí)現(xiàn)了Iterator trait的結(jié)構(gòu)體,每次迭代都會(huì)返回一個(gè)char類型的值。
fn main() { let slice = "Hello, 霸都"; for c in slice.chars() { println!("{}", c); } }
另外,字符串切片還包括非常多實(shí)用的方法。
- is_empty():檢查字符串切片是否為空。
- bytes():返回一個(gè)迭代器,可以遍歷字符串字節(jié)。
- starts_with(&prefix)、ends_with(&suffix):檢查字符串切片是否以指定前綴或后綴開始/結(jié)束。
- find(subslice):查找子字符串,并返回其索引(如果存在);否則,返回None。
- contains(char) 、contains(&str):檢查字符串切片中是否存在指定字符或子字符串。
- split(char)、split_whitespace():根據(jù)指定分隔符創(chuàng)建迭代器,每次迭代返回一個(gè)新字符串切片。
- trim()、trim_start()、trim_end():移除字符串切片開頭、結(jié)尾處的空白字符。
- to_lowercase()、to_uppercase():轉(zhuǎn)換為小寫或大寫字母形式。
這些方法具體如何使用,可參考下面的示例代碼。
fn main() { let slice: &str = ""; assert!(slice.is_empty()); for c in "Hello, 中國(guó)".chars() { println!("{}", c); } for byte in "hello, 中國(guó)".bytes() { println!("{}", byte); } let slice: &str = "Hello, CSDN"; assert!(slice.starts_with("Hello")); assert!(slice.ends_with("CSDN")); let index = "Hello, CSDN".find(","); assert_eq!(index, Some(5)); let contains1 = "Hello, CSDN".contains("Hello"); let contains2 = "Hello, CSDN".contains('D'); assert!(contains1 && contains2); // 輸出:Hello和CSDN for word in "Hello, CSDN".split(',') { println!("{}", word.trim()); } let trimmed = " Hello, CSDN ".trim(); assert_eq!(trimmed, "Hello, CSDN"); let lowercased = "Hello, CSDN".to_lowercase(); assert_eq!(lowercased, "hello, csdn"); }
總結(jié)
最后,我們來總結(jié)一下切片的特性,主要有以下幾點(diǎn)。
1、引用類型:切片是一種引用類型,它允許我們以引用的方式訪問連續(xù)內(nèi)存的數(shù)據(jù)。
2、沒有所有權(quán):切片本身并不擁有數(shù)據(jù),而是對(duì)數(shù)據(jù)的一種引用或視圖。這意味著切片不會(huì)復(fù)制數(shù)據(jù),而是直接引用原始數(shù)據(jù),沒有拷貝數(shù)據(jù)的額外開銷。
3、連續(xù)內(nèi)存:切片引用的是一段連續(xù)的內(nèi)存分配,而不是整個(gè)集合。這使得切片能夠安全、高效地訪問數(shù)組,而無需復(fù)制數(shù)據(jù)。
4、可變與不可變:切片可以是可變的,也可以是不可變的,這取決于它們所引用的數(shù)據(jù)的可變性。可變切片允許修改引用的數(shù)據(jù),而不可變切片則不允許。
5、索引與迭代:切片可以使用數(shù)字索引來訪問其中的元素,索引從0開始計(jì)數(shù)。此外,切片還支持迭代,可以使用迭代器來遍歷切片中的元素。
到此這篇關(guān)于一文弄懂Rust之切片的文章就介紹到這了,更多相關(guān)Rust 切片內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入探究在Rust中函數(shù)、方法和關(guān)聯(lián)函數(shù)有什么區(qū)別
在 Rust 中,函數(shù)、方法和關(guān)聯(lián)函數(shù)都是用來封裝行為的,它們之間的區(qū)別主要在于它們的定義和調(diào)用方式,本文將通過一個(gè)簡(jiǎn)單的rust代碼示例來給大家講講Rust中函數(shù)、方法和關(guān)聯(lián)函數(shù)區(qū)別,需要的朋友可以參考下2023-08-08Rust 連接 SQLite 數(shù)據(jù)庫(kù)的過程解析
本文通過一個(gè)例子給大家介紹了Rust 連接 SQLite 數(shù)據(jù)庫(kù)的詳細(xì)過程,我使用rusqlite這個(gè)crate,對(duì)Rust 連接 SQLite 數(shù)據(jù)庫(kù)相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2022-01-01Rust調(diào)用Windows API 如何獲取正在運(yùn)行的全部進(jìn)程信息
本文介紹了如何使用Rust調(diào)用WindowsAPI獲取正在運(yùn)行的全部進(jìn)程信息,通過引入winapi依賴并添加相應(yīng)的features,可以實(shí)現(xiàn)對(duì)不同API集的調(diào)用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-11-11使用cargo install安裝Rust二進(jìn)制工具過程
cargoinstall是一個(gè)用于安裝包含可執(zhí)行目標(biāo)的Rust包的命令行工具,類似于系統(tǒng)軟件包管理器,但它為Rust開發(fā)者提供了一種簡(jiǎn)潔的方式來安裝和管理命令行工具,安裝后,二進(jìn)制文件會(huì)存儲(chǔ)在$HOME/.cargo/bin目錄中,需要將該目錄添加到$PATH環(huán)境變量中才能在命令行中直接運(yùn)行2025-02-02Rust 數(shù)據(jù)分析利器polars用法詳解
這篇文章主要介紹了Rust 數(shù)據(jù)分析利器polars用法詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-08-08