题目来自 A Gentle Introduction To Rust[1]
File: rust/library/core/src/num/dec2flt/common.rs
在Rust源代码中,rust/library/core/src/num/dec2flt/common.rs的作用是定义了一些用于十进制到浮点数转化的共享逻辑。以下是对该文件内容的详细介绍:
- BiasedFp: 这是一个结构体,代表一个被偏置的浮点数。它有三个字段:
BiasedFp结构体的主要作用是将十进制表示的浮点数转化为IEEE 754标准表示的浮点数。通过将十进制的尾数和指数转化为二进制表示,并加上偏置,可以得到IEEE 754的浮点数表示。
- digits: 一个64位整数,表示浮点数的十进制尾数部分的位表示。
- exp: 一个有符号整数,表示浮点数的指数部分。
- exp_shift: 一个无符号整数,表示浮点数的指数偏移量。
- ByteSlice: 这是一个trait,扩展了标准库中的slice::SliceIndex[2] trait。它有三个关联类型:
ByteSlice trait的主要作用是为了支持字节操作的切片索引。它定义了一些通用的方法,例如get_unchecked、get_mut_unchecked和index等,用于进行切片操作,并提供了一些类型别名和常量,使其更易用。
- Output: 表示一个切片的返回类型。
- Error: 用于表示切片索引错误的类型。
- Bytes: 用于表示切片元素的类型。
- LexicalDigit: 这是一个trait,定义了数字字符与其对应的值之间的映射关系。它有两个方法:
LexicalDigit trait的主要作用是支持数字字符和数值之间的相互转化。该trait在公共的基础上定义了两个具体的实现:DecDigit和HexDigit。
- value: 根据数字字符返回对应的值。
- digit: 根据值返回对应的数字字符。
总之,rust/library/core/src/num/dec2flt/common.rs文件定义了十进制到浮点数转化的共享逻辑,包括将十进制表示的浮点数转化为IEEE 754标准表示的浮点数以及支持字节操作的切片索引。通过使用BiasedFp结构体和ByteSlice trait,可以方便地进行相关操作。
File: rust/library/core/src/num/dec2flt/mod.rs
在Rust源代码中,rust/library/core/src/num/dec2flt/mod.rs文件的作用是实现将十进制字符串解析为浮点数的功能。该文件中定义了用于解析和转换十进制字符串的函数和类型。
首先,mod.rs文件中定义了ParseFloatError结构体。ParseFloatError是一个表示解析浮点数过程中可能发生错误的类型。它使用标准库的Error trait实现了错误处理功能,因此可以通过使用Result类型返回解析结果。
ParseFloatError结构体拥有以下几个主要的属性和方法:
- kind: FloatErrorKind类型的枚举变量,用于描述错误类型。
- pub(crate) fn new(kind: FloatErrorKind) -> ParseFloatError: 用于创建一个新的ParseFloatError实例。
- pub(crate) fn kind(&self) -> FloatErrorKind: 用于获取ParseFloatError实例的错误类型。
FloatErrorKind是一个枚举类型,它定义了ParseFloatError可能的错误类型。该枚举定义了三种错误类型:
- Empty: 表示输入的字符串为空。
- EmptyMantissa: 表示输入的小数部分为空。
- Invalid: 表示输入的字符串无效。
此外,mod.rs文件中还定义了一系列用于解析和转换十进制字符串的函数和辅助类型。这些函数和类型包括:
- pub(crate) fn from_parts(components: Components) -> Result<f32, ParseFloatError>: 根据输入的十进制字符串的组件(符号位、小数部分、指数部分等)返回对应的f32浮点数。
- pub(crate) fn round_float(value: &BigRational, round: Rounding) -> BigRational: 将一个大数有理数四舍五入为最接近的整数。
- pub(crate) struct Components: 通过解析输入的字符串,将其分解为符号位、小数部分和指数部分等组件。
- pub(crate) type Rounding = Fn(&Integer, &Integer, i64) -> BigInt: Rounding是一个函数类型,用于将有理数四舍五入到最接近的整数。
总之,rust/library/core/src/num/dec2flt/mod.rs文件的作用是提供将十进制字符串解析为浮点数的功能,并定义了在解析过程中可能出现的错误类型和辅助函数。
File: rust/library/core/src/num/f64.rs
f64.rs
是 Rust 的核心库中的一个文件,定义了 f64
类型的相关功能和操作。
在 Rust 中,f64
是表示双精度浮点数(double-precision floating point number)的类型。它是一种用于表示带有小数部分的数值的数据类型,可以存储的范围更广、精度更高,但占用的存储空间也更大。
f64.rs
文件的主要作用是定义了 f64
类型的方法、实现和运算符重载,以提供对 f64
类型进行各种数值操作的支持。以下是该文件中的一些重要部分和功能:
f64
结构体定义:定义了f64
结构体,表示一个双精度浮点数。该结构体包含一个inner
字段,用于存储实际的浮点数值。- 常量和特殊值:定义了一些常用的
f64
常量和特殊值,如零值、最小值、最大值、非数值 (NaN) 等。 - 方法和运算符重载:在
f64
结构体上定义了各种方法和运算符重载函数,以支持对f64
类型的使用。这些方法包括数值运算(加减乘除、取余等)、比较操作(等于、大于、小于等)、取整(向上取整、向下取整等)、转换(转为整型、转为字节等)等。 - 实现特性:为了更好地集成到 Rust 的泛型和特性系统中,
f64.rs
还实现了一些特性(traits),如Num
、NumCast
、Bounded
等。这些特性定义了一些通用的数值操作和转换,使得f64
类型可以与其他类型进行协同工作。
总之,f64.rs
文件定义了 Rust 中 f64
类型的相关功能和操作,为开发者提供了丰富的数值计算和操作支持。开发者可以使用 f64
类型进行浮点数的计算、比较、转换等操作,并通过各种方法和运算符重载来实现所需的功能。
File: rust/library/core/src/num/mod.rs
在Rust的源代码中,rust/library/core/src/num/mod.rs文件是Rust标准库中的num模块的入口文件。该模块定义了各种数值类型的基本操作和算法。
具体来说,该文件包含了以下内容:
- Rust的数值类型:定义了各种整数类型、浮点数类型和复数类型。
- FromStrRadixHelper trait:该trait定义了用于将字符串解析为指定进制下的数值的方法。它包含了parse方法,可以将字符串解析为指定进制的数值类型。
- parse方法:用于将字符串解析为指定进制的数值类型。
- FpCategory enum:该enum定义了浮点数的几个特殊类别,用于判断浮点数的类型。它包含以下几个变种:
- Nan:表示非数值(NaN,Not-a-Number)。
- Infinite:表示无穷大值。
- Zero:表示零值。
- Subnormal:表示非规范化值。
- Normal:表示规范化值。
这些trait和enum的作用如下:
- FromStrRadixHelper trait允许将字符串解析为指定进制下的数值类型。它提供了一个通用的方法来解析各种数值类型,可以根据需要进行扩展和实现。
- FpCategory enum用于描述浮点数的特殊类别,可以用于判断浮点数的类型。这在编写数值计算和科学计算等涉及浮点数的程序中非常有用,可以根据浮点数的类别来执行不同的操作和处理。
总之,rust/library/core/src/num/mod.rs文件是Rust标准库中num模块的入口文件,定义了各种数值类型的基本操作和算法,以及一些用于数值解析和浮点数分类的trait和enum。
File: rust/library/core/src/bool.rs
在Rust源代码中,rust/library/core/src/bool.rs
文件的作用是定义了Rust中的bool
类型以及与其相关的操作、方法和实现。
在Rust中,bool
类型代表了布尔值,只有两个可能的值:true
和false
。该文件首先定义了bool
类型的结构体,其表示方式与C语言中的布尔类型类似,不同之处在于bool
类型在Rust中是原生类型,而不是通过宏或特殊函数实现的。
在bool.rs
文件中,我们可以找到bool
类型的一些常见操作和方法的实现。这些操作包括逻辑与(&&
)、逻辑或(||
)、逻辑非(!
)以及位异或(^
)等。这些操作符可以直接应用于bool
类型的变量。
此外,bool
类型还提供了一些有用的方法。例如,bool
类型实现了FromStr
trait,可以通过parse
方法将字符串解析为bool
类型的值。bool
类型还实现了PartialOrd
和PartialEq
trait,使得我们可以进行比较操作,例如判断两个bool
值是否相等。
总结起来,rust/library/core/src/bool.rs
文件的作用是定义了Rust中的bool
类型以及与其相关的操作、方法和实现。这个文件为Rust中布尔类型的使用和操作提供了基础。
File: rust/library/core/src/tuple.rs
在Rust源代码中,rust/library/core/src/tuple.rs
这个文件是实现了元组(tuple)数据结构的模块。元组是一种可以包含多个不同类型的值的数据结构。
该文件中定义了一个名为TupleN
的结构体,其中N
表示元组中包含的元素个数。TupleN
是元组的具体实现,它使用了[T; N]
类型来存储元组中的元素。此外,为了方便起见,TupleN
还实现了一些重要的trait以支持元组的常见操作。
下面是几个重要的trait及其作用:
Eq
:用于比较两个元组的相等性。元组中的每个元素都必须实现Eq
trait才能进行比较。PartialEq
:用于比较两个元组的相等性,不同之处在于可以进行部分比较。元组中的每个元素都必须实现PartialEq
trait才能进行比较。Ord
:用于进行元组的全序比较。元组中的每个元素都必须实现Ord
trait才能进行比较。PartialOrd
:用于进行元组的部分序比较。元组中的每个元素都必须实现PartialOrd
trait才能进行比较。Clone
:用于克隆一个元组,创建一个具有相同值的新元组。所有元组中的元素都必须实现Clone
trait才能进行克隆。Copy
:用于复制一个元组,创建一个完全相同的新元组。所有元组中的元素都必须实现Copy
trait才能进行复制。Debug
:用于将元组转换为可打印的调试输出格式。通过实现Debug
trait,我们可以在使用调试宏(如println!
)时打印出元组的内容。
这些trait的实现使得元组在Rust中成为一个非常强大的数据结构,可以进行比较、克隆、复制和调试等操作。rust/library/core/src/tuple.rs
文件的作用是为这些功能的实现提供了相应的代码定义。
Interfaces for working with Errors.
Error Handling In Rust
The Rust language provides two complementary systems for constructing / representing, reporting, propagating, reacting to, and discarding errors. These responsibilities are collectively known as "error handling." The components of the first system, the panic runtime and interfaces, are most commonly used to represent bugs that have been detected in your program. The components of the second system, Result
, the error traits, and user defined types, are used to represent anticipated runtime failure modes of your program.
The Panic Interfaces
The following are the primary interfaces of the panic system and the responsibilities they cover:
- [
panic!
] andpanic_any
(Constructing, Propagated automatically) PanicInfo
(Reporting)set_hook
,take_hook
, and#[panic_handler]
(Reporting)catch_unwind
andresume_unwind
(Discarding, Propagating)
The following are the primary interfaces of the error system and the responsibilities they cover:
- [
Result
] (Propagating, Reacting) - The [
Error
] trait (Reporting) - User defined types (Constructing / Representing)
match
anddowncast
(Reacting)- The question mark operator (
?
) (Propagating) - The partially stable
Try
traits (Propagating, Constructing) Termination
(Reporting)
Converting Errors into Panics
The panic and error systems are not entirely distinct. Often times errors that are anticipated runtime failures in an API might instead represent bugs to a caller. For these situations the standard library provides APIs for constructing panics with an Error
as its source.
- [
Result::unwrap
] - [
Result::expect
]
These functions are equivalent, they either return the inner value if theResult
is Ok
or panic if the Result
is Err
printing the inner error as the source. The only difference between them is that with expect
you provide a panic error message to be printed alongside the source, whereasunwrap
has a default message indicating only that you unwrapped an Err
.
Of the two, expect
is generally preferred since its msg
field allows you to convey your intent and assumptions which makes tracking down the source of a panic easier. unwrap
on the other hand can still be a good fit in situations where you can trivially show that a piece of code will never panic, such as "127.0.0.1".parse::<std::net::IpAddr>().unwrap()
or early prototyping.
Common Message Styles
There are two common styles for how people word expect
messages. Using the message to present information to users encountering a panic ("expect as error message") or using the message to present information to developers debugging the panic ("expect as precondition").
In the former case the expect message is used to describe the error that has occurred which is considered a bug. Consider the following example:
代码语言:javascript复制// Read environment variable, panic if it is not present
let path = std::env::var("IMPORTANT_PATH").unwrap();
In the "expect as error message" style we would use expect to describe that the environment variable was not set when it should have been:
代码语言:javascript复制let path = std::env::var("IMPORTANT_PATH")
.expect("env variable `IMPORTANT_PATH` is not set");
In the "expect as precondition" style, we would instead describe the reason we expect the Result
should be Ok
. With this style we would prefer to write:
let path = std::env::var("IMPORTANT_PATH")
.expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`");
The "expect as error message" style does not work as well with the default output of the std panic hooks, and often ends up repeating information that is already communicated by the source error being unwrapped:
代码语言:javascript复制thread 'main' panicked at src/main.rs:4:6:
env variable `IMPORTANT_PATH` is not set: NotPresent
In this example we end up mentioning that an env variable is not set, followed by our source message that says the env is not present, the only additional information we're communicating is the name of the environment variable being checked.
The "expect as precondition" style instead focuses on source code readability, making it easier to understand what must have gone wrong in situations where panics are being used to represent bugs exclusively. Also, by framing our expect in terms of what "SHOULD" have happened to prevent the source error, we end up introducing new information that is independent from our source error.
代码语言:javascript复制thread 'main' panicked at src/main.rs:4:6:
env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent
In this example we are communicating not only the name of the environment variable that should have been set, but also an explanation for why it should have been set, and we let the source error display as a clear contradiction to our expectation.
Hint: If you're having trouble remembering how to phrase expect-as-precondition style error messages remember to focus on the word "should" as in "env variable should be set by blah" or "the given binary should be available and executable by the current user".
File: rust/library/core/src/option.rs
在Rust源代码中,rust/library/core/src/option.rs
这个文件的作用是定义了Rust的标准库中的 Option
类型。Option 是一个枚举类型,用于表示一个可能存在或不存在的值。
Item<A>
, Iter<'a>
, IterMut<'a>
, IntoIter<A>
是 Option 类型的相关结构体。它们分别用于处理 Option 的某些特定情况:
Item<A>
是一个用于内部迭代的结构体,用于处理 Option 中存在的值 A。Iter<'a>
是一个用于不可变迭代的结构体,用于在 Option 为 Some 时提供对值的引用。IterMut<'a>
是一个用于可变迭代的结构体,用于在 Option 为 Some 时提供对值的可变引用。IntoIter<A>
是一个用于迭代所有权的结构体,用于在 Option 为 Some 时提供值的所有权。
SpecOptionPartialEq
是一个特定的 trait,用于在比较 Option 类型时提供部分相等性的实现。它包含了比较两个 Option 是否 None 或其中的值是否相等的函数。
Option<T>
是一个枚举类型,用于表示一个可能存在或不存在的值。Option可以有两种取值:Some(T)
表示存在一个具体的值 T,None
表示不存在一个具体值。Option提供了一些方法来处理这两种情况,例如 unwrap()
用于获取 Option 中的值,map()
用于对 Option 中的值进行转换等。
总之,option.rs
文件中定义了 Option 类型及其相关的结构体和 trait,提供了一种在 Rust 中处理可能存在或不存在值的方式。它是 Rust 标准库中非常常用的类型之一,用于增加代码的可靠性和安全性。
File: rust/library/core/src/error.rs
在Rust源代码中,rust/library/core/src/error.rs文件的作用是定义与错误处理相关的结构和trait。该文件包含了一系列用于构建和表示错误的结构体以及用于处理错误的trait。
下面是对各个结构体和trait的详细介绍:
- Internal: 这个结构体用于表示内部错误。它包含一个字符串用于描述错误,并提供了一个构造函数用于创建新的内部错误实例。
- Request<'a>(dyn Value, MaybeSizedValue, Ref(PhantomData)): 这个结构体是一个泛型结构体,用于表示通用的请求错误。它包含了一个动态类型的值、一个可能有大小的值和一个引用的对象,并使用泛型参数进行类型标记。
- TaggedOption<'a, Source<'a>>: 这个结构体用于表示带标记的选项和错误来源。它包含一个带有标记的值和一个错误来源,用于标识和追踪错误的来源。
- Error: 这个trait定义了表示错误的通用接口。所有具体的错误类型都必须实现这个trait,以便可以统一处理它们,并提供错误的相关信息。
- Type<'a>: 这个trait定义了错误类型的接口。它包含了获取错误类型名称的方法,并提供了一个默认的实现。
- MaybeSizedType<'a>: 这个trait定义了可能具有大小的错误类型的接口。它特定于泛型类型,并提供了获取错误类型名称和大小的方法。
- Erased<'a>: 这个trait定义了被擦除(erased)的错误类型的接口。它提供了获取擦除错误类型的类型注释和错误来源的方法。
这些结构体和trait的目的是为了提供一套标准的错误处理机制,在Rust中处理错误更加简洁和灵活。通过定义通用的错误接口和相关的类型和方法,可以方便地处理和表示不同类型的错误,并提供错误的相关信息和追踪来源。这些结构体和trait的设计也符合Rust语言的安全性和性能要求。
File: rust/library/core/src/cell.rs
在Rust源代码中,rust/library/core/src/cell.rs文件是Rust标准库中的一个模块,定义了几个Cell类型,用于在多线程环境下提供可变性和内部可变性的安全封装。
以下是这些struct的作用和用途:
- Cell: Cell是一个单线程内部可变的容器,允许在不可变引用的上下文中修改其值。它提供了一些原子操作,例如get和set,用于安全地修改和访问内部值。适用于在单线程的上下文中需要修改和访问可变属性的场景。
- RefCell: RefCell是一个在运行时检查借用规则的容器类型,用于在多线程环境中提供内部可变性。允许通过borrow和borrow_mut方法,在不同的上下文中借用mut和shared引用,并在运行时检查借用规则的合法性。适用于需要在多线程环境下修改和访问可变属性的场景。
- BorrowError: BorrowError是一个错误类型,表示在RefCell借用规则检查期间出现借用错误的情况。这个错误可以在RefCell的borrow方法中返回。
- BorrowMutError: BorrowMutError是一个错误类型,表示在RefCell借用规则检查期间出现可变借用错误的情况。这个错误可以在RefCell的borrow_mut方法中返回。
- BorrowRef<'b>: BorrowRef是一个借用的生命周期,用于表示RefCell的共享引用,可以通过调用borrow方法创建。
- Ref<'b, T>: Ref是一个在RefCell上的不可变借用的封装,它实现了Safe Deref Trait,可以像普通引用一样对其进行操作和访问。
- BorrowRefMut<'b>: BorrowRefMut是一个可变借用的生命周期,用于表示RefCell的可变引用,可以通过调用borrow_mut方法创建。
- RefMut<'b, T>: RefMut是一个在RefCell上的可变借用的封装,它实现了Safe Deref Mut Trait,与Ref类似,但允许对其进行修改。
- UnsafeCell: UnsafeCell是一个没有线程安全检查的内存单元类型,可以用于创建Rust中的内部可变数据结构。它是Cell和RefCell的底层基础,用于提供内部可变性的原始支持。
- SyncUnsafeCell: SyncUnsafeCell是一个基于UnsafeCell的同步版本的内部可变容器,允许在多线程环境中修改和访问内部值。与UnsafeCell类似,但它用于在多线程环境中提供内部可变性的原始支持。
总结来说,Cell和RefCell是Rust中用于实现内部可变性的重要工具。它们提供了在多线程环境下安全地修改和访问可变属性的机制,并在运行时检查借用规则的合法性。这些struct的设计目的是为了在保证线程安全的同时提供更灵活的可变性支持,确保代码的正确性和性能。
File: rust/library/core/src/cell/lazy.rs
在Rust中,rust/library/core/src/cell/lazy.rs
这个文件定义了一个名为LazyCell<T>
的结构体和一个名为State<T>
的枚举。
LazyCell<T>
结构体的作用是提供一种延迟初始化的方式,它允许在需要的时候才初始化其内部的值。这在某些情况下可以提高性能,因为它避免了不必要的初始化开销。
LazyCell<T>
结构体具有以下几个主要方法:
new()
:创建一个新的LazyCell<T>
实例。borrow()
:返回一个LazyCellPtr<T>
指向存储的值的借用。如果值尚未初始化,则返回None
。borrow_mut()
:返回一个LazyCellPtrMut<T>
指向存储的值的可变借用。如果值尚未初始化,则返回None
。into_inner()
:获取存储的值的所有权,如果值尚未初始化,则会引发Panic
。fill()
:使用给定的初始化函数初始化值。try_fill()
:使用给定的FnOnce
初始化函数尝试初始化值,如果已经初始化,则不执行任何操作。
State<T>
枚举是LazyCell<T>
内部使用的状态标记,用于跟踪值的初始化状态。它有以下几个变体:
Uninitialized
:表示值尚未初始化。Initializing
:表示值正在初始化。Initialized(T)
:表示值已经成功初始化,并包含实际的值。Poisoned
:表示在初始化期间发生了错误。
这些状态标记在LazyCell<T>
内部用于实现延迟初始化的逻辑。当LazyCell<T>
的方法被调用时,它将根据当前状态采取相应的行动,例如返回一个值的借用、初始化值、获取值的所有权等。
总的来说,rust/library/core/src/cell/lazy.rs
中定义的LazyCell<T>
结构体和State<T>
枚举提供了一种延迟初始化值的机制,在某些情况下可以提高性能和资源利用率。
File: rust/library/core/src/cell/once.rs
在Rust源代码中,once.rs
文件位于rust/library/core/src/cell
目录下,其作用是提供了一个可初始化一次的单线程容器OnceCell<T>
。以下是对once.rs
文件和相关结构体作用的详细介绍:
Once
结构体:Once
是一个用于记录初始化状态的标记,用于在多线程环境下确保某个操作只执行一次。它的主要作用是提供call_once
方法,该方法接收一个闭包并确保它只会执行一次。once_cell
模块:该模块包含了对OnceCell<T>
结构体的定义和实现。OnceCell
是一个容器,它只允许初始化一次,并提供了一些方法来操作和获取其内部的值。具体来说,OnceCell<T>
提供了以下方法:new()
:创建一个空的OnceCell
实例。get(&self) -> Option<&T>
:获取存储在OnceCell
中的值的不可变引用。如果OnceCell
为空,则返回None
。get_mut(&mut self) -> Option<&mut T>
:获取存储在OnceCell
中的值的可变引用。如果OnceCell
为空,则返回None
。set(&self, value: T) -> Result<(), T>
:将值存储到OnceCell
中。如果OnceCell
已经有了一个值,那么存储操作将失败,并返回旧值。set_once(&self, value: T) -> Result<(), T>
:类似于set
方法,但是只能在OnceCell
为空时才能成功。如果OnceCell
中已经有了一个值,则存储操作将失败,并返回旧值。into_inner(self) -> Option<T>
:将存储在OnceCell
中的值取出并返回,同时将OnceCell
重置为空。into_inner_with(self, f: F) -> T
:函数f
返回一个新值,并将旧值和新值一起存储在OnceCell
中。如果OnceCell
为空,则直接存储新值。
OnceCell<T>
在某些场景下非常有用,特别是在需要延迟初始化的情况下。通过使用OnceCell
结构体,可以确保变量只被初始化一次,并且在之后的调用中都使用相同的值。这在一些性能要求较高的场景中非常有用,因为可以避免重复的初始化操作。
Panics the current thread.
This allows a program to terminate immediately and provide feedback to the caller of the program.
This macro is the perfect way to assert conditions in example code and in tests. panic!
is closely tied with the unwrap
method of both`Option`[3] and `Result`[4] enums. Both implementations callpanic!
when they are set to [None
] or [Err
] variants.
When using panic!()
you can specify a string payload that is built using [formatting syntax]. That payload is used when injecting the panic into the calling Rust thread, causing the thread to panic entirely.
The behavior of the default std
hook, i.e. the code that runs directly after the panic is invoked, is to print the message payload tostderr
along with the file/line/column information of the panic!()
call. You can override the panic hook using std::panic::set_hook()
. Inside the hook a panic can be accessed as a &dyn Any Send
, which contains either a &str
or String
for regular panic!()
invocations. (Whether a particular invocation contains the payload at type &str
or String
is unspecified and can change.) To panic with a value of another other type, panic_any
can be used.
See also the macro [compile_error!
], for raising errors during compilation.
When to use panic!
vs Result
The Rust language provides two complementary systems for constructing / representing, reporting, propagating, reacting to, and discarding errors. These responsibilities are collectively known as "error handling." panic!
andResult
are similar in that they are each the primary interface of their respective error handling systems; however, the meaning these interfaces attach to their errors and the responsibilities they fulfill within their respective error handling systems differ.
The panic!
macro is used to construct errors that represent a bug that has been detected in your program. With panic!
you provide a message that describes the bug and the language then constructs an error with that message, reports it, and propagates it for you.
Result
on the other hand is used to wrap other types that represent either the successful result of some computation, Ok(T)
, or error types that represent an anticipated runtime failure mode of that computation, Err(E)
.Result
is used alongside user defined types which represent the various anticipated runtime failure modes that the associated computation could encounter. Result
must be propagated manually, often with the help of the?
operator and Try
trait, and they must be reported manually, often with the help of the Error
trait.
For more detailed information about error handling check out the [book] or thestd::result
module docs.
Current implementation
If the main thread panics it will terminate all your threads and end your program with code 101
.
Editions
Behavior of the panic macros changed over editions.
2021 and later
In Rust 2021 and later, panic!
always requires a format string and the applicable format arguments, and is the same in core
and std
. Use `std::panic::panic_any(x)`[5] to panic with an arbitrary payload.
2018 and 2015
In Rust Editions prior to 2021, std::panic!(x)
with a single argument directly uses that argument as a payload. This is true even if the argument is a string literal. For example, panic!("problem: {reason}")
panics with a payload of literally "problem: {reason}"
(a &'static str
).
core::panic!(x)
with a single argument requires that x
be &str
, but otherwise behaves like std::panic!
. In particular, the string need not be a literal, and is not interpreted as a format string.
Examples
代码语言:javascript复制# #![allow(unreachable_code)]
panic!();
panic!("this is a terrible mistake!");
panic!("this is a {} {message}", "fancy", message = "message");
std::panic::panic_any(4); // panic with the value of 4 to be collected elsewhere
File: rust/library/core/src/macros/mod.rs
在Rust源代码中,rust/library/core/src/macros/mod.rs
这个文件的作用是定义了一些重要的宏(macros),这些宏在Rust语言的编译器中被广泛地使用。
宏是一种类似于函数的代码抽象机制,它允许程序员在编译时进行代码的生成和转换,以及执行预定义的模式匹配和操作。宏通过以macro_rules!
关键字开头,并设置模式匹配规则来定义,可以接受不同的参数并生成相应的代码。
在rust/library/core/src/macros/mod.rs
文件中,可以看到许多以def
开头的宏定义,这些宏提供了库级别的基础设施。以下是一些重要的宏和它们的作用:
char!()
:它是一个用于字符字面量的宏,用法类似于'c'
。这个宏通过字节字面量创建一个字符。format_args!()
:它是一个用于格式化字符串的宏,用法类似于println!()
或format!()
。这个宏接受一个格式化字符串和一系列参数,并生成格式化后的结果。index!()
:它是一个用于实现索引操作的宏,用法类似于my_vec[index]
。这个宏通过调用类型的index()
方法来实现索引操作。println!()
和print!()
:它们是用于在控制台打印输出的宏,用法与相应的标准库函数类似。这些宏允许程序员在运行时向终端输出文本。assert!()
和assert_eq!()
:它们是用于断言和测试的宏,用法类似于assert!(condition)
或assert_eq!(a, b)
。这些宏可以用于验证程序的正确性和实现自动化测试。
此外,rust/library/core/src/macros/mod.rs
文件中还定义了其他一些实用的宏,如dbg!()
(用于在调试时打印变量和表达式的值)、if_let!()
(用于模式匹配和条件判断的简写形式)等等。这些宏提供了一种编写更加简洁和灵活的代码的方式,使得Rust语言在表达能力和编写风格上更加丰富和可扩展。
总之,rust/library/core/src/macros/mod.rs
文件中的宏定义了Rust语言的一些核心功能,包括字符字面量、格式化字符串、索引操作、打印输出、断言和测试等等。这些宏为Rust编译器的功能提供了强大的支持和灵活性,使得开发者能够更加方便地编写高效、安全和可读性强的代码。
File: rust/library/core/src/default.rs
在Rust中,rust/library/core/src/default.rs
是标准库中的一个文件,它定义了 Default
这个 trait。
Default
这个 trait 在 Rust 中有着重要的作用,它提供了一种定义类型默认值的机制。如果一个类型实现了 Default
trait,那么就可以通过 Default::default()
方法来创建该类型的默认实例。这样做的好处是,在很多场景下不需要手动为每个字段设置默认值。通过调用 Default::default()
方法,就可以创建一个已经设置好默认值的实例。
Default
trait 定义了一个方法 default()
,它返回一个给定类型的默认实例。默认实例的值是类型自身的默认值,就像通过 Default
trait 创建实例时不带任何参数一样。标准库中已经为大部分基本类型和常用集合类型实现了 Default
trait,这样这些类型的默认值就可以直接通过 Default::default()
方法获取。
在 Rust 中,通过实现 Default
trait 可以为自定义类型提供默认值的能力。比如,一个自定义的结构体可以实现 Default
trait,设置每个字段的默认值。当需要创建这个结构体实例时,可以直接使用 Default::default()
方法,而无需为每个字段指定具体的初始值。
此外,Default
trait 在泛型编程中也很有用。通过对泛型类型实现 Default
trait,可以在不知道具体类型的情况下,为泛型类型提供默认值。这对于许多算法和数据结构的实现是非常有帮助的。
总结一下,Default
这个 trait 在 Rust 中的作用是定义类型的默认值,通过实现 Default
trait,可以为类型提供默认值的能力。通过调用 Default::default()
方法,可以创建一个已经设置好默认值的实例。这个 trait 对于提高代码的简洁性和灵活性非常有帮助。
File: rust/library/core/src/any.rs
在Rust中,rust/library/core/src/any.rs
文件的作用是定义了与类型相关的特性、类型以及与类型信息相关的功能。
该文件中定义了三个与类型相关的结构体:TypeId
、ThreadId
和TypeInfo
。
TypeId
结构体代表一个类型的唯一标识符。它是一个实现了Copy
和Eq
特性的结构体,因此可以直接进行复制和比较。TypeId
的主要作用是在运行时唯一标识一个类型。ThreadId
结构体代表一个线程的唯一标识符。类似于TypeId
,ThreadId
也是实现了Copy
和Eq
特性的结构体。ThreadId
的作用是在多线程环境中唯一标识一个线程。TypeInfo
结构体代表一个类型的详细信息。它包含了类型的名称、大小以及对齐方式等。TypeInfo
结构体通常通过type_of
函数获取,该函数接受一个静态类型作为参数并返回对应类型的TypeInfo
。
除了上述结构体,该文件还定义了与类型相关的几个特性,即Any
、AnyMut
和TypeIdTrait
。
Any
特性是由dyn Any
类型实现的,它允许在运行时检查和转换类型。通过Any
特性,可以将任意具体类型转换为&dyn Any
类型的引用,并使用downcast_ref
和downcast_mut
函数来将其转换回原始类型。AnyMut
特性是由dyn Any Send Sync
类型实现的,它与Any
特性类似,但还添加了线程安全的要求。通过AnyMut
特性,可以将任意具体类型转换为&mut dyn Any
类型的引用,并使用downcast_mut
函数来将其转换回原始类型。TypeIdTrait
特性是core::any::TypeId
类型实现的,它是用来表示某个具体类型的唯一标识符。TypeIdTrait
特性的主要作用是提供了类型标识符的比较功能,通过比较两个TypeIdTrait
实例,可以判断它们是否代表同一个类型。
总之,rust/library/core/src/any.rs
文件定义了与类型相关的特性和类型,以及可以在运行时获取和操作类型信息的功能。这些功能对于通用编程、类型检查和类型转换等场景非常有用。
File: rust/library/core/src/ffi/c_str.rs
在Rust源代码中,rust/library/core/src/ffi/c_str.rs
文件的作用是处理C字符串的转换和操作功能,以及与C字符串相关的错误处理。下面会详细介绍其中的结构体和枚举。
- CStr结构体:它表示一个不包含null终止符的C字符串,它是一个零内存开销的类型,封装了一个不可变的指向以null字节结尾的字节数组的指针,并提供了C字符串的方法和操作。
- FromBytesWithNulError结构体:表示从字节数组中创建CStr时可能出现的错误。当字节数组没有以null字节结尾时,会生成此错误。它提供了方法来访问错误的索引,从而可以在错误处理时提供更多信息。
- FromBytesUntilNulError结构体:表示从字节数组中创建CStr时可能出现的错误。当字节数组中没有null字节时,会生成此错误。它也提供了方法来访问错误的索引。
- FromBytesWithNulErrorKind枚举:它是FromBytesWithNulError的一个内部枚举,用于标识错误的种类。它包含以下几个值:
- InteriorNul:表示字节数组中存在null字节。
- NotNulTerminated:表示字节数组没有以null字节结尾。
这些结构体和枚举提供了方便的方式来处理C字符串转换和相关错误。通过使用它们,可以在Rust代码中与C代码进行交互或操作C字符串时更加安全和可靠。
Equivalent to C's signed long
(long
) type.
This type will always be [i32
] or [i64
]. Most notably, many Linux-based systems assume an i64
, but Windows assumes i32
. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an int
, although in practice, no system would have a long
that is neither an i32
nor i64
.
Equivalent to C's unsigned short
type.
This type will almost always be [u16
], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a short
.
Equivalent to C's unsigned int
type.
This type will almost always be [u32
], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an int
; some systems define it as a [u16
], for example.
Equivalent to C's signed short
(short
) type.
This type will almost always be [i16
], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as i32
, for example.
Equivalent to C's signed char
type.
This type will always be [i8
], but is included for completeness. It is defined as being a signed integer the same size as a C char
.
Equivalent to C's unsigned long long
type.
This type will almost always be [u64
], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a long long
, although in practice, no system would have a long long
that is not a u64
, as most systems do not have a standardised [u128
] type.
Equivalent to C's unsigned char
type.
This type will always be [u8
], but is included for completeness. It is defined as being an unsigned integer the same size as a C char
.
Equivalent to C's signed int
(int
) type.
This type will almost always be [i32
], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a short
; some systems define it as an [i16
], for example.
Equivalent to C's void
type when used as a [pointer].
In essence, *const c_void
is equivalent to C's const void*
and *mut c_void
is equivalent to C's void*
. That said, this isnot the same as C's void
return type, which is Rust's ()
type.
To model pointers to opaque types in FFI, until extern type
is stabilized, it is recommended to use a newtype wrapper around an empty byte array. See the [Nomicon] for details.
One could use std::os::raw::c_void
if they want to support old Rust compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by this definition. For more information, please read RFC 2521.
Equivalent to C's char
type.
C's char
type is completely unlike Rust's char
type; while Rust's type represents a unicode scalar value, C's char
type is just an ordinary integer. On modern architectures this type will always be either [i8
] or [u8
], as they use byte-addresses memory with 8-bit bytes.
C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character '