本書github鏈接:
inside-rust-std-library
前面章節(jié)參見:
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(序言) - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(一 概述) - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(二 內(nèi)存)—Layout/原生指針 - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(二 內(nèi)存)—NonNull<T>/申請及釋放 - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(二 內(nèi)存)—mem模塊/MaybeUninit<T> - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核 (三 基礎(chǔ)Trait) 編譯器內(nèi)置Trait - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(三 基礎(chǔ)Trait)— Ops Trait - 簡書 (jianshu.com)
深入RUST標(biāo)準(zhǔn)庫內(nèi)核(三 基本Trait)—Range - 簡書 (jianshu.com)
RUST的Index 運算符代碼分析
數(shù)組下標(biāo)符號[]由Index, IndexMut兩個Trait完成重載棒呛。數(shù)組下標(biāo)符號重載使得程序更有可讀性机蔗。兩個Trait如下定義:
pub trait Index<Idx: ?Sized> {
/// The returned type after indexing.
type Output: ?Sized;
/// 若果傳入的參數(shù)超過內(nèi)存界限將馬上引發(fā)panic
fn index(&self, index: Idx) -> &Self::Output;
}
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
}
切片數(shù)據(jù)結(jié)構(gòu)[T]的Index實現(xiàn)
impl<T, I> ops::Index<I> for [T]
where
I: SliceIndex<[T]>,
{
type Output = I::Output;
fn index(&self, index: I) -> &I::Output {
index.index(self)
}
}
impl<T, I> ops::IndexMut<I> for [T]
where
I: SliceIndex<[T]>,
{
fn index_mut(&mut self, index: I) -> &mut I::Output {
index.index_mut(self)
}
}
需要依賴SliceIndex Trait實現(xiàn)[T]的ops::Index。SliceIndex主要是為了實現(xiàn)下標(biāo)即支持用usize類型取出單一元素敷存,又支持用Range類型取出子slice肩杈。
顯然柴我,針對不同的Index<Idx>中的泛型Idx,需要實現(xiàn)不同的處理邏輯扩然。SliceIndex的引入是典型的處理這個需求的設(shè)計方式艘儒。即如果對某一類型實現(xiàn)一個具有泛型的Trait時,如果對于Trait的泛型實例化不同類型,會帶來處理邏輯的不同界睁。那就再定義一個輔助Trait觉增,為前Trait的實例化類型實現(xiàn)輔助Trait,在這個輔助Trait的實現(xiàn)中實現(xiàn)不同的處理邏輯翻斟。輔助Trait和Trait之間的定義相關(guān)性即可參考SliceIndex和Index的定義相關(guān)性逾礁。
mod private_slice_index {
use super::ops;
//在私有模塊中定義一個Sealed Trait,后繼的SliceIndex繼承Sealed访惜。
//帶來的結(jié)果是只有在本模塊實現(xiàn)了Sealed Trait的類型才能實現(xiàn)SliceIndex
//即使SliceIndex是公有定義嘹履,其他類型仍然不能夠?qū)崿F(xiàn)SliceIndex
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for ops::Range<usize> {}
impl Sealed for ops::RangeTo<usize> {}
impl Sealed for ops::RangeFrom<usize> {}
impl Sealed for ops::RangeFull {}
impl Sealed for ops::RangeInclusive<usize> {}
impl Sealed for ops::RangeToInclusive<usize> {}
impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
}
pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
/// 此類型通常為T或者T的引用,切片债热,原生指針類型
type Output: ?Sized;
// 從slice變量中用self獲取Option<Output>變量
fn get(self, slice: &T) -> Option<&Self::Output>;
fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;
//slice是序列的頭指針砾嫉,后面的具體實現(xiàn)會看到為什么用 *const T
unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
//如果self超出slice的安全范圍,會panic
fn index(self, slice: &T) -> &Self::Output;
fn index_mut(self, slice: &mut T) -> &mut Self::Output;
}
unsafe impl<T> SliceIndex<[T]> for usize {
type Output = T;
fn get(self, slice: &[T]) -> Option<&T> {
// 必須轉(zhuǎn)化為*const T才能夠用指針加方式來獲取
if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
}
fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
}
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
//相當(dāng)于C的指針加操作
unsafe { slice.as_ptr().add(self) }
}
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
unsafe { slice.as_mut_ptr().add(self) }
}
fn index(self, slice: &[T]) -> &T {
// N.B., use intrinsic indexing 此處應(yīng)該可以用get,但應(yīng)該是編譯器內(nèi)置支持窒篱,為了效率直接使用了內(nèi)置的數(shù)組下標(biāo)表示焕刮。
&(*slice)[self]
}
fn index_mut(self, slice: &mut [T]) -> &mut T {
// N.B., use intrinsic indexing
&mut (*slice)[self]
}
}
以上就是針對[T]的以無符號數(shù)作為下標(biāo)取出單一元素的ops::Index 及 ops::IndexMut的底層實現(xiàn),從slice中取出單一元素必須應(yīng)用ptr的操作舌剂。
unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
type Output = [T];
fn get(self, slice: &[T]) -> Option<&[T]> {
if self.start > self.end || self.end > slice.len() {
None
} else {
unsafe { Some(&*self.get_unchecked(slice)) }
}
}
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
if self.start > self.end || self.end > slice.len() {
None
} else {
unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
}
}
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// 利用ptr的內(nèi)存操作形成* const [T] 原生指針
unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
}
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
unsafe {
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
}
}
fn index(self, slice: &[T]) -> &[T] {
if self.start > self.end {
slice_index_order_fail(self.start, self.end);
} else if self.end > slice.len() {
slice_end_index_len_fail(self.end, slice.len());
}
//將* const [T]轉(zhuǎn)化為切片引用
unsafe { &*self.get_unchecked(slice) }
}
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
if self.start > self.end {
slice_index_order_fail(self.start, self.end);
} else if self.end > slice.len() {
slice_end_index_len_fail(self.end, slice.len());
}
unsafe { &mut *self.get_unchecked_mut(slice) }
}
}
以上是實現(xiàn)用Range從slice中取出子slice的實現(xiàn)济锄。其他如RangeTo等與Range大同小異。
小結(jié)
對于切片的Index, 整體上霍转,需要將切片類型的引用轉(zhuǎn)換為slice元素類型的原生指針荐绝,然后對原生指針做加減操作,再根據(jù)需要重新建立元素類型或作切片類型的原生指針避消,然后將原生指針轉(zhuǎn)換為引用低滩。由此可見,ptr和mem模塊的熟練使用是必須掌握的岩喷。
數(shù)組數(shù)據(jù)結(jié)構(gòu)[T;N]的ops::Index實現(xiàn)
impl<T, I, const N: usize> Index<I> for [T; N]
where
[T]: Index<I>,
{
type Output = <[T] as Index<I>>::Output;
fn index(&self, index: I) -> &Self::Output {
Index::index(self as &[T], index)
}
}
impl<T, I, const N: usize> IndexMut<I> for [T; N]
where
[T]: IndexMut<I>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
IndexMut::index_mut(self as &mut [T], index)
}
}
以上恕沫, self as &[T]
即把[T;N]轉(zhuǎn)化為了切片[T], 所以數(shù)組的Index就是[T]的Index實現(xiàn)