國外做家譜的網(wǎng)站開發(fā)小程序
1、什么是切片
在 Rust 中,切片(slice)是一種基本類型和序列類型。在 Rust 官方文檔中,切片被定義為“對連續(xù)序列的動態(tài)大小視圖”。
但在rust的Github 源碼中切片被定義如下:
切片是對一塊內(nèi)存的視圖,表示為指針和長度。
其實這個定義更有幫助。從這里的定義可以知道,切片是一個“寬指針”(fat pointer)。所以基本上,當(dāng)創(chuàng)建一個數(shù)組的切片時,切片包含以下內(nèi)容:
- 指向數(shù)組中切片起始元素地址的指針
- 描述切片長度的值
2、切片示例
在 Rust 中,切片可以是對支持的數(shù)組的視圖,也可以是對其他序列(例如向量或字符串)的視圖。如果切片是對字符串的視圖,它被稱為字符串切片或字符串字面量,并且通常以其借用形式 &str
出現(xiàn)。
以下是一個示例數(shù)組和該數(shù)組生成的兩個切片:
左邊和右邊展示了對中間顯示的數(shù)組提供視圖的兩個切片。數(shù)組和切片的定義如下:
let array: [i32; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let slice1 = &array[5..10];
let slice2 = &array[3..7];
從上圖可以看到,在 slice1
中,切片的指針指向數(shù)組的索引 5。slice1
的長度為 5。這意味著切片將包含數(shù)組中的 5 個元素。下面是切片相關(guān)的索引和值。切片本身的索引從 0 到 4。
右側(cè)是 slice2
。該切片的指針指向元素 3,且切片的長度為 4。
3、切片常規(guī)操作
定義一個數(shù)組,然后對數(shù)組進行切片操作:
let array: [i32; 7] = [0, 1, 2, 3, 4, 5, 6];let slice = &array[..]; // [ 0, 1, 2, 3, 4, 5, 6 ]
let slice = &array[0..3]; // [ 0, 1, 2 ]
let slice = &array[..3]; // [ 0, 1, 2 ]
let slice = &array[2..4]; // [ 2, 3 ]
let slice = &array[2..]; // [ 2, 3, 4, 5, 6 ]
上面定義了不可變數(shù)組以及創(chuàng)建數(shù)組切片的幾種方法。在切片定義后的注釋中展示了 dbg!(slice); 的輸出結(jié)果。
之后再創(chuàng)建一個可變的切片:
let mut array: [i32; 7] = [0, 1, 2, 3, 4, 5, 6];
let array_slice = &mut array[0..5]; // [ 0, 1, 2, 3, 4 ]
檢查切片的長度并迭代索引/值:
slice.len(); // 5for (index, item) in slice.iter().enumerate() {println!("index: {:?} element {:?}", index, item);
}
/*
index: 0 element 0
index: 1 element 1
index: 2 element 2
index: 3 element 3
index: 4 element 4
*/
從切片中檢索一個值:
slice[1]; // 1
切片的長度在編譯時并不總是已知的。如果訪問超出邊界的索引值,編譯器將不會保存:
slice[100];
會報如下錯誤:
thread ‘main’ panicked at ‘index out of bounds: the len is 5 but the index is 100’
為了安全地從切片中獲取值,可以使用 get() 方法:
slice.get(2); // Some(2)
slice.get(100); // None
在切片中查找值:
slice.iter().position(|v| v == &120); // None
slice.iter().position(|v| v == &4); // Some(4)
改變切片中元素的值:
slice[0] = 100;
dbg!(slice); // [100, 1, 2, 3, 4]
dbg!(array); // [100, 1, 2, 3, 4, 5, 6]
4.對不同類型的切片進行操作
可以從數(shù)組、向量和字符串中獲取切片:
let array: [i32; 4] = [0, 1, 2, 3];
let array_slice = &array[..2]; // [0, 1]
let vector = vec![1, 2, 3, 4];
let vector_slice = &vector[0..2]; // [1, 2]
let string = String::from("string slice");
let string_slice = &string[0..6]; // "string"
println!("{:?} {:?} {:?}", array_slice, vector_slice, string_slice);
// [0, 1] [1, 2] "string"
之前定義的數(shù)組和向量包含 i32 類型,之后可以創(chuàng)建一個同時適用于 vector_slice
和 array_slice
的函數(shù):
fn return_second(n: &[i32]) {println!("{}", n[1]);
}
return_second(array_slice); // 1
return_second(vector_slice); // 2
字符串切片是一個 &str,因此不能將其傳遞給 return_second 函數(shù)。事實上,字符串切片有點特殊。在 Rust 中,所有的字符串都是 UTF-8 編碼的,因此字符的大小可以不同。iter() 方法不能用在字符串切片上,相反,需要使用 chars() 方法。要從切片中取第 n 個字符,則需要使用索引 n。
let string = String::from("Rust is 😍");
let string_slice = &string[..];fn return_second_char(n: &str) {println!("{:?}", n.chars().nth(1));
}return_second_char(string_slice); // Some('u')for c in string_slice.chars() {println!("{}", c)
}
/*
R
u
s
ti
s😍
*/
for (i, c) in string_slice.chars().enumerate() {println!("{} {}", i, c)
}
/*
0 R
1 u
2 s
3 t
4
5 i
6 s
7
8 😍
*/
5.指針
Rust中的寬指針(fat pointers)與窄指針(thin pointers)是指針類型的兩種概念。
-
窄指針(Thin Pointers):指針僅包含目標(biāo)內(nèi)存地址信息,不包含其他附加信息。比如,裸指針
*const T
和*mut T
就是窄指針,它們只存儲指向某個類型T
的內(nèi)存地址。 -
寬指針(Fat Pointers):指針除了存儲目標(biāo)內(nèi)存地址外,還包含其他信息,例如動態(tài)數(shù)組的長度。切片
&[T]
或者動態(tài) trait 對象&dyn Trait
就是寬指針的例子,它們除了指向內(nèi)存的地址外,還存儲著長度等其他信息。
寬指針包含更多的信息,但也會帶來一些額外的存儲開銷。窄指針更加輕量,但缺乏一些額外的信息。在Rust中,切片是一種寬指針,因為它包含指向數(shù)據(jù)的指針和數(shù)據(jù)長度。
use std::mem;
let array: [i32; 500] = [0; 500];
let slice = &array[..];
let array_pointer = &array;
let slice_pointer = &slice;
let start_of_array_slice = &array[0];
println!("--------------------------------------------");
println!("array_pointer address: {:p}", array_pointer);
println!("slice_pointer address: {:p}", slice_pointer);
println!("start_of_array_slice address: {:p}", start_of_array_slice);
println!("slice occupies {} bytes", mem::size_of_val(&slice));
println!("array_pointer occupies {} bytes",mem::size_of_val(&array_pointer)
);
println!("array occupies {} bytes", mem::size_of_val(&array));
println!("--------------------------------------------");
--------------------------------------------
array_pointer address: 0x9def68
slice_pointer address: 0x9df738
start_of_array_slice address: 0x9def68
slice occupies 16 bytes
array_pointer occupies 8 bytes
array occupies 2000 bytes
--------------------------------------------
數(shù)組的總大小為 2000 字節(jié)。整個數(shù)組的切片(寬指針)占據(jù) 16 字節(jié)。如果獲取數(shù)組的指針,得到的是一個占據(jù) 8 字節(jié)的窄指針。數(shù)組指針和切片起始地址的內(nèi)存地址是相同的。