免费图标下载网站,凡客诚品官方商城,wordpress商城多重分类,韩国小清新网站模板数值特性库入口文件为lib.rs。该文件定义一系列数字特性的trait#xff08;特征#xff09;#xff0c;这些特性可以被不同的数字类型实现#xff0c;从而提供一套通用的数值操作方法。下面是对代码中关键部分的解释#xff1a;
一、基础设置
#![doc(html_root_url “h…数值特性库入口文件为lib.rs。该文件定义一系列数字特性的trait特征这些特性可以被不同的数字类型实现从而提供一套通用的数值操作方法。下面是对代码中关键部分的解释
一、基础设置
#![doc(html_root_url “https://docs.rs/num-traits/0.2”)]指定了文档的根URL用于在线文档生成。#![deny(unconditional_recursion)]禁止无条件递归这是一种编译时检查防止无限递归。#![no_std]表明这个crate不依赖Rust标准库使其可以在没有标准库的环境如裸机或嵌入式系统中使用。
二、条件编译
#[cfg(feature “std”)]当启用std特性时编译这部分代码。这通常用于在有无标准库支持时提供不同的实现。
三、引入依赖
引入了Rust核心库中的一些基本功能如格式化fmt、包装类型Wrapping、基本的算术操作Add, Div, Mul, Rem, Sub等及其赋值操作AddAssign, DivAssign, MulAssign, RemAssign, SubAssign。
四、公开的特性
通过pub use语句公开了库中定义的一系列特性traits和常量使得外部可以直接通过这些路径访问它们。例如Bounded用于表示有边界的数字类型Float和FloatConst提供了浮点数的操作和常量NumCast用于类型转换等。
五、核心trait定义:
Num定义了数值类型的基础特性包括比较、基本数值操作、字符串转换等。NumOps为实现了基本算术运算符, -, *, /, %的类型自动实现。NumRef和RefNum提供了对引用类型数值操作的支持。NumAssignOps为实现了赋值运算符如, -的类型自动实现。
六、宏和模块:
通过#[macro_use]引入了宏定义在macros模块中这些宏可能用于简化代码或提供额外的功能。定义了多个模块如bounds, cast, float, identities, int, ops, pow, real, sign每个模块都负责特定的数值操作或特性。
七、总结及源码
整体而言这段代码定义了一个丰富的数字特性库为Rust中的数值类型提供了一套通用的接口和操作方法。通过实现这些trait不同的数值类型可以享受到这些通用操作带来的便利同时也为开发者提供了一种灵活的方式来处理不同类型的数值。源码如下
//为泛型准备的数字特征库 #![doc(html_root_url https://docs.rs/num-traits/0.2)]
#![deny(unconditional_recursion)]
#![no_std]// 需要显式地将crate引入固有的float方法。Need to explicitly bring the crate in for inherent float methods
#[cfg(feature std)]
extern crate std;use core::fmt;
use core::num::Wrapping;
use core::ops::{Add, Div, Mul, Rem, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};pub use crate::bounds::Bounded; // 1 边界特性
#[cfg(any(feature std, feature libm))]
pub use crate::float::Float; // 2
pub use crate::float::FloatConst; // 3pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; // 4
pub use crate::identities::{one, zero, ConstOne, ConstZero, One, Zero}; // 5
pub use crate::int::PrimInt; // 6
pub use crate::ops::bytes::{FromBytes, ToBytes}; // 7
pub use crate::ops::checked::{CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
}; // 8
pub use crate::ops::euclid::{CheckedEuclid, Euclid}; // 9
pub use crate::ops::inv::Inv; // 10
pub use crate::ops::mul_add::{MulAdd, MulAddAssign}; // 11
pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; // 12
pub use crate::ops::wrapping::{WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
}; // 13
pub use crate::pow::{checked_pow, pow, Pow}; // 14
pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned}; // 15#[macro_use]
mod macros;pub mod bounds;
pub mod cast;
pub mod float;
pub mod identities;
pub mod int;
pub mod ops;
pub mod pow;
pub mod real;
pub mod sign;/// The base trait for numeric types, covering 0 and 1 values,
/// comparisons, basic numeric operations, and string conversion.
pub trait Num: PartialEq Zero One NumOps {type FromStrRadixErr;/// Convert from a string and radix (typically 2..36).////// # Examples////// rust/// use num_traits::Num;////// let result i32 as Num::from_str_radix(27, 10);/// assert_eq!(result, Ok(27));////// let result i32 as Num::from_str_radix(foo, 10);/// assert!(result.is_err());/// ////// # Supported radices////// The exact range of supported radices is at the discretion of each type implementation. For/// primitive integers, this is implemented by the inherent from_str_radix methods in the/// standard library, which **panic** if the radix is not in the range from 2 to 36. The/// implementation in this crate for primitive floats is similar.////// For third-party types, it is suggested that implementations should follow suit and at least/// accept 2..36 without panicking, but an Err may be returned for any unsupported radix./// Its possible that a type might not even support the common radix 10, nor any, if string/// parsing doesnt make sense for that type.fn from_str_radix(str: str, radix: u32) - ResultSelf, Self::FromStrRadixErr;
}/// Generic trait for types implementing basic numeric operations
///
/// This is automatically implemented for types which implement the operators.
pub trait NumOpsRhs Self, Output Self:AddRhs, Output Output SubRhs, Output Output MulRhs, Output Output DivRhs, Output Output RemRhs, Output Output
{
}implT, Rhs, Output NumOpsRhs, Output for T whereT: AddRhs, Output Output SubRhs, Output Output MulRhs, Output Output DivRhs, Output Output RemRhs, Output Output
{
}/// The trait for Num types which also implement numeric operations taking
/// the second operand by reference.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumRef: Num forr NumOpsr Self {}
implT NumRef for T where T: Num forr NumOpsr T {}/// The trait for Num references which implement numeric operations, taking the
/// second operand either by value or by reference.
///
/// This is automatically implemented for all types which implement the operators. It covers
/// every type implementing the operations though, regardless of it being a reference or
/// related to Num.
pub trait RefNumBase: NumOpsBase, Base forr NumOpsr Base, Base {}
implT, Base RefNumBase for T where T: NumOpsBase, Base forr NumOpsr Base, Base {}/// Generic trait for types implementing numeric assignment operators (like ).
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssignOpsRhs Self:AddAssignRhs SubAssignRhs MulAssignRhs DivAssignRhs RemAssignRhs
{
}implT, Rhs NumAssignOpsRhs for T whereT: AddAssignRhs SubAssignRhs MulAssignRhs DivAssignRhs RemAssignRhs
{
}/// The trait for Num types which also implement assignment operators.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssign: Num NumAssignOps {}
implT NumAssign for T where T: Num NumAssignOps {}/// The trait for NumAssign types which also implement assignment operations
/// taking the second operand by reference.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssignRef: NumAssign forr NumAssignOpsr Self {}
implT NumAssignRef for T where T: NumAssign forr NumAssignOpsr T {}macro_rules! int_trait_impl {($name:ident for $($t:ty)*) ($(impl $name for $t {type FromStrRadixErr ::core::num::ParseIntError;#[inline]fn from_str_radix(s: str, radix: u32)- ResultSelf, ::core::num::ParseIntError{$t::from_str_radix(s, radix)}})*)
}
int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
int_trait_impl!(Num for isize i8 i16 i32 i64 i128);implT: Num Num for WrappingT
whereWrappingT: NumOps,
{type FromStrRadixErr T::FromStrRadixErr;fn from_str_radix(str: str, radix: u32) - ResultSelf, Self::FromStrRadixErr {T::from_str_radix(str, radix).map(Wrapping)}
}#[derive(Debug)]
pub enum FloatErrorKind {Empty,Invalid,
}
// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
// so theres not really any way for us to reuse it.
#[derive(Debug)]
pub struct ParseFloatError {pub kind: FloatErrorKind,
}impl fmt::Display for ParseFloatError {fn fmt(self, f: mut fmt::Formatter_) - fmt::Result {let description match self.kind {FloatErrorKind::Empty cannot parse float from empty string,FloatErrorKind::Invalid invalid float literal,};description.fmt(f)}
}fn str_to_ascii_lower_eq_str(a: str, b: str) - bool {a.len() b.len() a.bytes().zip(b.bytes()).all(|(a, b)| {let a_to_ascii_lower a | (((bA a a bZ) as u8) 5);a_to_ascii_lower b})
}// FIXME: The standard library from_str_radix on floats was deprecated, so were stuck
// with this implementation ourselves until we want to make a breaking change.
// (would have to drop it from Num though)
macro_rules! float_trait_impl {($name:ident for $($t:ident)*) ($(impl $name for $t {type FromStrRadixErr ParseFloatError;fn from_str_radix(src: str, radix: u32)- ResultSelf, Self::FromStrRadixErr{use self::FloatErrorKind::*;use self::ParseFloatError as PFE;// Special case radix 10 to use more accurate standard library implementationif radix 10 {return src.parse().map_err(|_| PFE {kind: if src.is_empty() { Empty } else { Invalid },});}// Special valuesif str_to_ascii_lower_eq_str(src, inf)|| str_to_ascii_lower_eq_str(src, infinity){return Ok(core::$t::INFINITY);} else if str_to_ascii_lower_eq_str(src, -inf)|| str_to_ascii_lower_eq_str(src, -infinity){return Ok(core::$t::NEG_INFINITY);} else if str_to_ascii_lower_eq_str(src, nan) {return Ok(core::$t::NAN);} else if str_to_ascii_lower_eq_str(src, -nan) {return Ok(-core::$t::NAN);}fn slice_shift_char(src: str) - Option(char, str) {let mut chars src.chars();Some((chars.next()?, chars.as_str()))}let (is_positive, src) match slice_shift_char(src) {None return Err(PFE { kind: Empty }),Some((-, )) return Err(PFE { kind: Empty }),Some((-, src)) (false, src),Some((_, _)) (true, src),};// The significand to accumulatelet mut sig if is_positive { 0.0 } else { -0.0 };// Necessary to detect overflowlet mut prev_sig sig;let mut cs src.chars().enumerate();// Exponent prefix and exponent index offsetlet mut exp_info None::(char, usize);// Parse the integer part of the significandfor (i, c) in cs.by_ref() {match c.to_digit(radix) {Some(digit) {// shift significand one digit leftsig * radix as $t;// add/subtract current digit depending on signif is_positive {sig (digit as isize) as $t;} else {sig - (digit as isize) as $t;}// Detect overflow by comparing to last value, except// if weve not seen any non-zero digits.if prev_sig ! 0.0 {if is_positive sig prev_sig{ return Ok(core::$t::INFINITY); }if !is_positive sig prev_sig{ return Ok(core::$t::NEG_INFINITY); }// Detect overflow by reversing the shift-and-add processif is_positive (prev_sig ! (sig - digit as $t) / radix as $t){ return Ok(core::$t::INFINITY); }if !is_positive (prev_sig ! (sig digit as $t) / radix as $t){ return Ok(core::$t::NEG_INFINITY); }}prev_sig sig;},None match c {e | E | p | P {exp_info Some((c, i 1));break; // start of exponent},. {break; // start of fractional part},_ {return Err(PFE { kind: Invalid });},},}}// If we are not yet at the exponent parse the fractional// part of the significandif exp_info.is_none() {let mut power 1.0;for (i, c) in cs.by_ref() {match c.to_digit(radix) {Some(digit) {// Decrease power one order of magnitudepower / radix as $t;// add/subtract current digit depending on signsig if is_positive {sig (digit as $t) * power} else {sig - (digit as $t) * power};// Detect overflow by comparing to last valueif is_positive sig prev_sig{ return Ok(core::$t::INFINITY); }if !is_positive sig prev_sig{ return Ok(core::$t::NEG_INFINITY); }prev_sig sig;},None match c {e | E | p | P {exp_info Some((c, i 1));break; // start of exponent},_ {return Err(PFE { kind: Invalid });},},}}}// Parse and calculate the exponentlet exp match exp_info {Some((c, offset)) {let base match c {E | e if radix 10 10.0,P | p if radix 16 2.0,_ return Err(PFE { kind: Invalid }),};// Parse the exponent as decimal integerlet src src[offset..];let (is_positive, exp) match slice_shift_char(src) {Some((-, src)) (false, src.parse::usize()),Some((, src)) (true, src.parse::usize()),Some((_, _)) (true, src.parse::usize()),None return Err(PFE { kind: Invalid }),};#[cfg(feature std)]fn pow(base: $t, exp: usize) - $t {Float::powi(base, exp as i32)}// otherwise uses the generic pow from the rootmatch (is_positive, exp) {(true, Ok(exp)) pow(base, exp),(false, Ok(exp)) 1.0 / pow(base, exp),(_, Err(_)) return Err(PFE { kind: Invalid }),}},None 1.0, // no exponent};Ok(sig * exp)}})*)
}
float_trait_impl!(Num for f32 f64);/// A value bounded by a minimum and a maximum
///
/// If input is less than min then this returns min.
/// If input is greater than max then this returns max.
/// Otherwise this returns input.
///
/// **Panics** in debug mode if !(min max).
#[inline]
pub fn clampT: PartialOrd(input: T, min: T, max: T) - T {debug_assert!(min max, min must be less than or equal to max);if input min {min} else if input max {max} else {input}
}/// A value bounded by a minimum value
///
/// If input is less than min then this returns min.
/// Otherwise this returns input.
/// clamp_min(std::f32::NAN, 1.0) preserves NAN different from f32::min(std::f32::NAN, 1.0).
///
/// **Panics** in debug mode if !(min min). (This occurs if min is NAN.)
#[inline]
#[allow(clippy::eq_op)]
pub fn clamp_minT: PartialOrd(input: T, min: T) - T {debug_assert!(min min, min must not be NAN);if input min {min} else {input}
}/// A value bounded by a maximum value
///
/// If input is greater than max then this returns max.
/// Otherwise this returns input.
/// clamp_max(std::f32::NAN, 1.0) preserves NAN different from f32::max(std::f32::NAN, 1.0).
///
/// **Panics** in debug mode if !(max max). (This occurs if max is NAN.)
#[inline]
#[allow(clippy::eq_op)]
pub fn clamp_maxT: PartialOrd(input: T, max: T) - T {debug_assert!(max max, max must not be NAN);if input max {max} else {input}
}#[test]
fn clamp_test() {// Int testassert_eq!(1, clamp(1, -1, 2));assert_eq!(-1, clamp(-2, -1, 2));assert_eq!(2, clamp(3, -1, 2));assert_eq!(1, clamp_min(1, -1));assert_eq!(-1, clamp_min(-2, -1));assert_eq!(-1, clamp_max(1, -1));assert_eq!(-2, clamp_max(-2, -1));// Float testassert_eq!(1.0, clamp(1.0, -1.0, 2.0));assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));assert_eq!(2.0, clamp(3.0, -1.0, 2.0));assert_eq!(1.0, clamp_min(1.0, -1.0));assert_eq!(-1.0, clamp_min(-2.0, -1.0));assert_eq!(-1.0, clamp_max(1.0, -1.0));assert_eq!(-2.0, clamp_max(-2.0, -1.0));assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
}#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_nan_min() {clamp(0., ::core::f32::NAN, 1.);
}#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_nan_max() {clamp(0., -1., ::core::f32::NAN);
}#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_nan_min_max() {clamp(0., ::core::f32::NAN, ::core::f32::NAN);
}#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_min_nan_min() {clamp_min(0., ::core::f32::NAN);
}#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_max_nan_max() {clamp_max(0., ::core::f32::NAN);
}#[test]
fn from_str_radix_unwrap() {// The Result error must impl Debug to allow unwrap()let i: i32 Num::from_str_radix(0, 10).unwrap();assert_eq!(i, 0);let f: f32 Num::from_str_radix(0.0, 10).unwrap();assert_eq!(f, 0.0);
}#[test]
fn from_str_radix_multi_byte_fail() {// Ensure parsing doesnt panic, even on invalid sign charactersassert!(f32::from_str_radix(™0.2, 10).is_err());// Even when parsing the exponent signassert!(f32::from_str_radix(0.2E™1, 10).is_err());
}#[test]
fn from_str_radix_ignore_case() {assert_eq!(f32::from_str_radix(InF, 16).unwrap(),::core::f32::INFINITY);assert_eq!(f32::from_str_radix(InfinitY, 16).unwrap(),::core::f32::INFINITY);assert_eq!(f32::from_str_radix(-InF, 8).unwrap(),::core::f32::NEG_INFINITY);assert_eq!(f32::from_str_radix(-InfinitY, 8).unwrap(),::core::f32::NEG_INFINITY);assert!(f32::from_str_radix(nAn, 4).unwrap().is_nan());assert!(f32::from_str_radix(-nAn, 4).unwrap().is_nan());
}#[test]
fn wrapping_is_num() {fn require_numT: Num(_: T) {}require_num(Wrapping(42_u32));require_num(Wrapping(-42));
}#[test]
fn wrapping_from_str_radix() {macro_rules! test_wrapping_from_str_radix {($($t:ty)) {$(for (s, r) in [(42, 10), (42, 2), (-13.0, 10), (foo, 10)] {let w Wrapping::$t::from_str_radix(s, r).map(|w| w.0);assert_eq!(w, $t as Num::from_str_radix(s, r));})};}test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
}#[test]
fn check_num_ops() {fn computeT: Num Copy(x: T, y: T) - T {x * y / y % y y - y}assert_eq!(compute(1, 2), 1)
}#[test]
fn check_numref_ops() {fn computeT: NumRef(x: T, y: T) - T {x * y / y % y y - y}assert_eq!(compute(1, 2), 1)
}#[test]
fn check_refnum_ops() {fn computeT: Copy(x: T, y: T) - Twherefora a T: RefNumT,{((((x * y) / y) % y) y) - y}assert_eq!(compute(1, 2), 1)
}#[test]
fn check_refref_ops() {fn computeT(x: T, y: T) - Twherefora a T: RefNumT,{((((x * y) / y) % y) y) - y}assert_eq!(compute(1, 2), 1)
}#[test]
fn check_numassign_ops() {fn computeT: NumAssign Copy(mut x: T, y: T) - T {x * y;x / y;x % y;x y;x - y;x}assert_eq!(compute(1, 2), 1)
}#[test]
fn check_numassignref_ops() {fn computeT: NumAssignRef Copy(mut x: T, y: T) - T {x * y;x / y;x % y;x y;x - y;x}assert_eq!(compute(1, 2), 1)
}