一文弄懂Rust之切片
概述
在Rust中,切片是一種非常重要的引用類型。它允許你安全地引用一段連續(xù)內(nèi)存中的數(shù)據(jù),而不需要擁有這些數(shù)據(jù)的所有權(quán)。切片不包含分配的內(nèi)存空間,它僅僅是一個(gè)指向數(shù)據(jù)開始位置和長度的數(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];
下面,我們詳細(xì)介紹切片聲明中的各個(gè)元素。
slice_name:切片變量取的名字。
[T; n]:是一個(gè)泛型,表示一個(gè)包含n個(gè)類型為T的元素的切片。但在實(shí)際聲明中,通常不需要指定n,因?yàn)镽ust會(huì)根據(jù)初始化的數(shù)據(jù)自動(dò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類型切片。注意:我們在這里顯式指定了切片的類型,因?yàn)榭涨衅旧聿话銐虻男畔碜詣?dòng)推斷類型。
fn main() {
let empty_slice: &[i32] = &[];
// 輸出:[]
println!("{:?}", empty_slice);
}切片的使用
1、獲取切片的長度,可以使用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, 中國".chars() {
println!("{}", c);
}
for byte in "hello, 中國".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ù)的可變性??勺兦衅试S修改引用的數(shù)據(jù),而不可變切片則不允許。
5、索引與迭代:切片可以使用數(shù)字索引來訪問其中的元素,索引從0開始計(jì)數(shù)。此外,切片還支持迭代,可以使用迭代器來遍歷切片中的元素。
到此這篇關(guān)于一文弄懂Rust之切片的文章就介紹到這了,更多相關(guān)Rust 切片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
rust 一個(gè)日志緩存記錄的通用實(shí)現(xiàn)方法
本文給出了一個(gè)通用的設(shè)計(jì)模式,通過建造者模式實(shí)例化記錄對(duì)象,可自定義格式化器將實(shí)例化后的記錄對(duì)象寫入到指定的緩存對(duì)象中,這篇文章主要介紹了rust 一個(gè)日志緩存記錄的通用實(shí)現(xiàn)方法,需要的朋友可以參考下2024-04-04

