赞
踩
本文摘自《深入RUST标准库》,已经全网发售,恳请支持
代码路径:
%USER%.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\intrinsic.rs
intrinsic库函数是指由编译器内置实现的函数,一般如下特点的函数用固有函数:
原子操作函数主要用于多核CPU,多线程CPU时对数据的原子操作。intrinsic库中atomic_xxx及atomic_xxx_xxx类型的函数即为原子操作函数。原子操作函数主要用于并发编程中做临界保护,并且是其他临界保护机制的基础,如Mutex,RWlock等。
各种整数及浮点的数学函数实现。这一部分放在intrinsic主要是因为现代CPU对浮点计算由很多支持,这些数学函数由汇编语言来实现更具备效率,那就有必要由编译器来内置实现。
断言类: assert_xxxx 类型的函数
函数栈:caller_location
intrinsic函数库是从编译器层面完成跨CPU架构的一个手段,intrinsic通常被上层的库所封装。但在操作系统编程和框架编程时,仍然会不可避免的需要接触。
原生数据类型,Option类型,Result类型的某些代码是分析其他模块的基础,因此先对这些类型的部分代码做个基础分析。
代码目录如下:
%USER%.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\num
整形数据类型标准函数库主要包括:
整形有有符号整形,无符号整形,大整形(大于计算机字长的整形),但基本内容都是实现以上方法
标准库用宏简化的对不同位长的无符号整形的方法实现。本文着重介绍若干不易注意的方法,如大小端转换,对数学方法仅给出加法做为代表。代码如下:
macro_rules! uint_impl {
($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr,
//以下主要是rust doc文档需要
$rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
这个宏实现所有无符号整形的方法:
pub const MIN: Self = 0;
//按位非
pub const MAX: Self = !0;
pub const BITS: u32 = $BITS;
以上是无符号整形的常量
//利用intrinsics的位函数完成整数的位操作相关函数,这里仅分析一个,其他请参考标准库手册
pub const fn count_ones(self) -> u32 {
intrinsics::ctpop(self as $ActualT) as u32
}
//其他位操作函数
...
...
字节序变换是网络编程与结构化数据文件的必须功能,RUST将之在整形的方法里实现:
//内部字节交换,后继大小端变换使用 pub const fn swap_bytes(self) -> Self { intrinsics::bswap(self as $ActualT) as Self } //big endian 到硬件架构字节序 pub const fn from_be(x: Self) -> Self { #[cfg(target_endian = "big")] { x } #[cfg(not(target_endian = "big"))] { x.swap_bytes() } } //little endian 转换为硬件架构字节序 pub const fn from_le(x: Self) -> Self { #[cfg(target_endian = "little")] { x } #[cfg(not(target_endian = "little"))] { x.swap_bytes() } } //硬件架构字节序到big endian pub const fn to_be(self) -> Self { // or not to be? #[cfg(target_endian = "big")] { self } #[cfg(not(target_endian = "big"))] { self.swap_bytes() } } //硬件架构字节序到little endian pub const fn to_le(self) -> Self { #[cfg(target_endian = "little")] { self } #[cfg(not(target_endian = "little"))] { self.swap_bytes() } } //获得大端字节序字节数组 pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] { self.to_be().to_ne_bytes() } //获得小端 pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] { self.to_le().to_ne_bytes() } //硬件平台字节序 pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] { unsafe { mem::transmute(self) } } //从big endian 字节数组获得类型值 pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) } //从little endian 字节数组获得类型值 pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) } //从硬件架构字节序字节数组获得类型值 pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self { unsafe { mem::transmute(bytes) } }
RUST的整数类形各种算术方法突出的展示了RUST对安全的极致关注。算术方法也更好的支持了链式调用的函数式编程风格。对于算术溢出,RUST给出了各种情况下的处理方案:
//对溢出做检查的加法运算,溢出情况下会返回wrapping_add的值,即溢出后值回绕 //这里每种类型运算都以加法为例,其他诸如减、乘、除、幂次请参考官方标准库手册 pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } //其他的对溢出做检查的数学运算,略 ... ... //溢出后对最大值取余,即回绕 pub const fn wrapping_add(self, rhs: Self) -> Self { intrinsics::wrapping_add(self, rhs) } //以边界值取余的其他数学运算方法,略 ... ... //饱和加法,超过边界值结果为边界值 pub const fn saturating_add(self, rhs: Self) -> Self { intrinsics::saturating_add(self, rhs) } //其他饱和型的数学运算,略 ... ... //对加法有效性检查的加法运算,如发生溢出,则返回异常 pub const fn checked_add(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_add(rhs); if unlikely!(b) {None} else {Some(a)} } //无检查add, 是 + 符号的默认调用函数。 pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { // 调用者要保证不发生错误 unsafe { intrinsics::unchecked_add(self, rhs) } } //其他对有效性检查的数学运算, 略 ... ... pub const fn min_value() -> Self { Self::MIN } pub const fn max_value() -> Self { Self::MAX } }
算术算法基本上是使用了intrinsics提供的函数。
下面用u8给出一个具体的实例
impl u8 { //利用宏实现 u8类型的方法 uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } pub const fn is_ascii(&self) -> bool { *self & 128 == 0 } //其他ASCII相关函数,请参考标准库手册,略 ... ... } //u16 数学函数方法 实现 impl u16 { uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } widening_impl! { u16, u32, 16, unsigned } } //其他无符号整形的实现,略 ... ...
RUST整形库代码逻辑并不复杂,宏也很简单。但因为RUST将其他语言的独立的数学库函数,单独的大小端变换等集成入整形(浮点类型),有可能造成出于习惯而无法找到相应的函数。
代码路径:
%USER%.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs
Option 主要用来在编程中,类型T的变量可以不存在,代表一种异常。以往会选择T类型的一个值代表不存在的异常情况,从而导致异常情况处理只能依赖于程序员,采用Option后,对异常情况的处理会由编译器负责。
在初始化时无法确定T类型的值时,除了MaybeUninit外,还可以用Option来声明变量并初始化为None。
Option主要是解封装方法及Try trait。但Option更酷的打开方式应该是用以map为代表的方法来完成函数链式调用。
从Option的标准库代码中可以发现,Option实际上是不属于RUST语言最基础的语法的,它是在RUST语言最基础的enum语法的基础上派生出来的一种库类型。这展示了RUST语言的一个设计思维,编译器仅仅做最基础的部分,其他的交由库来解决。实际上,在学习RUST时,很多重要的常用类型都是标准库提供并解决了非常多的需求。如RefCell, Arc等。需要细心地体会和学习RUST如何构建这些基础设施并养成习惯。
Option的若干重点方法源代码如下:
impl<T> Option<T> {
//当希望获取Option封装的变量的借用的时候,使用这个函数
//&Option<T> 转换为Option<&T>以取得能够真正操作的引用
//因为Option可能为None,所以返回值只能是Option<&T>
pub const fn as_ref(&self) -> Option<&T> {
match *self {
Some(ref x) => Some(x),
None => None,
}
}
//类似于as_ref,但返回的是可变引用
pub const fn as_mut(&mut self) -> Option<&mut T> {
//略
}
以下解封装函数,看过源码后功能即一目了然,因为解封装用过于常用,因此将全部的解封装代码都给出
//解封装函数,None时输出指定的错误信息并退出程序 pub fn expect(self, msg: &str) -> T { match self { Some(val) => val, None => expect_failed(msg), } } //解封装函数,None时输出固定的错误信息并退出程序 pub const fn unwrap(self) -> T { match self { Some(val) => val, None => panic!("called `Option::unwrap()` on a `None` value"), } } //解封装,None时返回给定的默认值 pub fn unwrap_or(self, default: T) -> T { match self { Some(x) => x, None => default, } } //解封装,None时调用给定的闭包函数 pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T { match self { Some(x) => x, None => f(), } } //确认不会为None时的解封装 pub unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_some()); match self { Some(val) => val, // SAFETY: the safety contract must be upheld by the caller. None => unsafe { hint::unreachable_unchecked() }, } }
针对函数式编程的链式调用设计的方法:
//主要用于函数式编程,在不解封装的情况下对Option的值进行处理,并按需要返回适合的类型 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { match self { Some(x) => Some(f(x)), None => None, } } //同上,None时返回默认值 pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U { match self { Some(t) => f(t), None => default, } } //同上,None时调用默认闭包函数 pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { match self { Some(t) => f(t), None => default(), } } //将Option转换为Result,也是为支持函数式编程 pub fn ok_or<E>(self, err: E) -> Result<T, E> { match self { Some(v) => Ok(v), None => Err(err), } } //同上,None时调用默认函数处理 pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> { match self { Some(v) => Ok(v), None => Err(err()), } } //主要还是应用于函数式编程,值是Some(x)的时候返回预设值 pub fn and<U>(self, optb: Option<U>) -> Option<U> { match self { Some(_) => optb, None => None, } } //主要用于函数式编程,与and 形成系列,值为Some(x)调用函数并返回函数值 pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> { match self { Some(x) => f(x), None => None, } } //如果是Some(x), 判断是否满足预设条件 pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self { if let Some(x) = self { if predicate(&x) { return Some(x); } } None } //如果是Some(x)返回本身,如果是None,返回预设值 pub fn or(self, optb: Option<T>) -> Option<T> { match self { Some(_) => self, None => optb, } } //如果是Some(x)返回本身,否则返回预设函数 pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> { match self { Some(_) => self, None => f(), } } //类似xor操作 pub fn xor(self, optb: Option<T>) -> Option<T> { match (self, optb) { //一方为Some,一方为None,返回Some值 (Some(a), None) => Some(a), (None, Some(b)) => Some(b), //两者都为Some,或两者都为None, 返回None _ => None, } }
其他方法
//不解封装的重新设置内部的值,并返回值的可变引用 //例子:let a = None; a.insert(1); //上例也是一种常用方法,利用None可以实现不知道初始值但需要有一个变量的情况。 pub fn insert(&mut self, value: T) -> &mut T { //原有*self会被drop *self = Some(value); //确认不会为None unsafe { self.as_mut().unwrap_unchecked() } } //使用一个闭包生成变量 pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T { if let None = *self { *self = Some(f()); } match self { //此处模式匹配有些特殊,详细请见后面的对结构体引用类型`&T/&mutT`的match语法研究 Some(v) => v, None => unsafe { hint::unreachable_unchecked() }, } } //mem::replace分析请参考前文,用None替换原来的变量,并用新变量返回self,同时也完成了所有权的转移 pub const fn take(&mut self) -> Option<T> { mem::replace(self, None) } //用新value替换原变量,并把原变量返回 pub const fn replace(&mut self, value: T) -> Option<T> { mem::replace(self, Some(value)) } //针对Option的zip操作 pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> { match (self, other) { (Some(a), Some(b)) => Some((a, b)), _ => None, } } //执行一个函数 pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R> where F: FnOnce(T, U) -> R, { //此处,顺序应该是先执行self? other?,然后再调用函数 Some(f(self?, other?)) } }
如下代码:
#[derive(Debug)]
struct TestStructA {a:i32, b:i32}
fn main() {
let c = TestStructA{a:1, b:2};
let d = [1,2,3];
match ((&c, &d)) {
(&e, &f) => println!("{:?} {:?}", e, f),
_ => println!("match nothing"),
}
}
以上代码编译时,会发生如下错误:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:9:7
|
9 | match (&c) {
| ^^^^
10 | (&e, &d) => println!("{:?}", e),
| --
| ||
| |data moved here
| |move occurs because `e` has type `TestStructA`, which does not implement the `Copy` trait
| help: consider removing the `&`: `e`
可见,如果match 引用,那对后继的绑定是有讲究的。对引用做match,本意便是不想要转移所有权。因此,在match的分支中就不能有引发所有权移动的绑定出现。
再请参考如下代码:
struct TestStructA {a:i32,b:i32}
fn main() {
let c = TestStructA{a:1, b:2};
let d = [1,2,3];
match ((&c, &d)) {
(&TestStructA{a:ref u, b:ref w}, &[ref x, ..]) => println!("{} {} {}", *u, *w, *x),
_ => println!("match nothing"),
}
}
如果不想转移所有权,那上面代码的match就应该是一个标准的写法,对结构内部的变量也需要用引用来绑定,尤其是结构内部变量如果没有实现Copy Trait,那就必须用引用,否则也会引发编译告警。
为了编码上的方便,RUST针对以上的代码,支持如下简化形式:
struct TestStructA {a:i32,b:i32}
fn main() {
let c = TestStructA{a:1, b:2};
let d = [1, 2, 3];
match ((&c, &d)) {
//对比上述代码,头部少了&,模式绑定内部少了 ref,但代码功能完全一致
(TestStructA{a: u, b: w}, [x,..]) => println!("{} {} {}", *u, *w, *x),
_ => println!("match nothing"),
}
}
如果不知道RUST的这个语义,很可能会对这里的类型绑定感到疑惑。
从实际的使用场景分析,对结构体引用做match,其目的就是对结构体内部的成员的引用做pattern绑定。而且如果结构体内部的成员不支持Copy,那也不可能对结构体成员做pattern绑定。所以,此语法也是在RUST的所有权定义下的一个必然的简化选择。
代码路径:
%USER%.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\result.rs
Result<T,E>采用了与Option类似的思路来处理函数或方法返回值存在异常的情况。
Result<T,E>的Try trait十分重要,另外,以map为代表的函数同样打开函数链式调用的通道。
Result<T,E>值得关注方法的源代码如下:
impl<T, E> Result<T, E> { //应用于函数式编程,如果是Ok, 利用闭包直接处理Result值,返回需要的新Result类型 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E> { match self { Ok(t) => Ok(op(t)), Err(e) => Err(e), } } //如果是Ok, 利用闭包处理Result值,返回需要的类型,如果是Err返回默认值 pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U { match self { Ok(t) => f(t), Err(_) => default, } } //如果是Ok, 调用闭包处理Result,返回需要的类型, 如果是Err,调用错误闭包函数处理错误 pub fn map_or_else<U, D: FnOnce(E) -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { match self { Ok(t) => f(t), Err(e) => default(e), } } //如果是Err, 调用闭包函数处理错误,返回需要的类型, Ok则返回原值 pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, F> { match self { Ok(t) => Ok(t), Err(e) => Err(op(e)), } } //Result传递,Ok则返回给定的Result类型值,否则返回原值 pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> { match self { Ok(_) => res, Err(e) => Err(e), } } //Ok 则调用闭包处理,返回需要的Result类型值, 否则返回原值 pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> { match self { Ok(t) => op(t), Err(e) => Err(e), } } //Ok返回原值,Err返回传入的默认Result类型值 pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> { match self { Ok(v) => Ok(v), Err(_) => res, } } //Ok返回原值,Err调用函数进行处理,返回需要的Result类型值 pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> { match self { Ok(t) => Ok(t), Err(e) => op(e), } } //解封装,Ok返回封装内的值,Err返回默认值 pub fn unwrap_or(self, default: T) -> T { match self { Ok(t) => t, Err(_) => default, } } //解封装, Ok返回封装内的值, Err调用处理函数处理 pub fn unwrap_or_else<F: FnOnce(E) -> T>(self, op: F) -> T { match self { Ok(t) => t, Err(e) => op(e), } } //确认返回一定是Ok时的解封装函数 pub unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_ok()); match self { Ok(t) => t, // SAFETY: the safety contract must be upheld by the caller. Err(_) => unsafe { hint::unreachable_unchecked() }, } } //确认返回一定是Err时调用的解封装函数 pub unsafe fn unwrap_err_unchecked(self) -> E { debug_assert!(self.is_err()); match self { // SAFETY: the safety contract must be upheld by the caller. Ok(_) => unsafe { hint::unreachable_unchecked() }, Err(e) => e, } } }
Result<T,E>的解封装函数如下:
impl<T, E: fmt::Debug> Result<T, E> { //解封装,Ok解封装,Err输出参数信息并退出 pub fn expect(self, msg: &str) -> T { match self { Ok(t) => t, Err(e) => unwrap_failed(msg, &e), } } //解封装,Ok解封装,Err输出固定信息并退出 pub fn unwrap(self) -> T { match self { Ok(t) => t, Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), } } } impl<T: fmt::Debug, E> Result<T, E> { //解封装,对于Ok输出参数指定的信息并退出,Err解封装 pub fn expect_err(self, msg: &str) -> E { match self { Ok(t) => unwrap_failed(msg, &t), Err(e) => e, } } //解封装,对于Ok输出固定的信息并退出,Err解封装 pub fn unwrap_err(self) -> E { match self { Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), Err(e) => e, } } } impl<T: Default, E> Result<T, E> { //解封装,Ok解封装, Err返回T的Default值 pub fn unwrap_or_default(self) -> T { match self { Ok(x) => x, Err(_) => Default::default(), } } } impl<T, E: Into<!>> Result<T, E> { //解封装,Ok解封装,Err返回Never类型 pub fn into_ok(self) -> T { match self { Ok(x) => x, Err(e) => e.into(), } } } impl<T: Into<!>, E> Result<T, E> { //解封装,Err解封装, Ok返回Never类型 pub fn into_err(self) -> E { match self { Ok(x) => x.into(), Err(e) => e, } } } impl<T, E> Result<Option<T>, E> { //将Result<>转换为Option pub const fn transpose(self) -> Option<Result<T, E>> { match self { Ok(Some(x)) => Some(Ok(x)), Ok(None) => None, Err(e) => Some(Err(e)), } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。