diff --git a/src/basic/base-type/numbers.md b/src/basic/base-type/numbers.md index 5e8d196f..1ca4d90c 100644 --- a/src/basic/base-type/numbers.md +++ b/src/basic/base-type/numbers.md @@ -4,13 +4,12 @@ 计算机和数值关联在一起的时间,远比我们想象的要长,因此数值类型可以说是有计算机以来就有的类型,下面内容将深入讨论 Rust 的数值类型以及相关的运算符。 -## 整数和浮点数 Rust 使用一个相对传统的语法来创建整数(`1`,`2`,...)和浮点数(`1.0`,`1.1`,...)。整数、浮点数的运算和你在其它语言上见过的一致,都是通过常见的运算符来完成。 > 不仅仅是数值类型,Rust 也允许在复杂类型上定义运算符,例如在自定义类型上定义 `+` 运算符,这种行为被称为运算符重载,Rust 具体支持的可重载运算符见[附录 B](https://course.rs/appendix/operators.html#运算符) -#### 整数类型 +## 整数类型 **整数**是没有小数部分的数字。之前使用过的 `i32` 类型,表示有符号的 32 位整数( `i` 是英文单词 _integer_ 的首字母,与之相反的是 `u`,代表无符号 `unsigned` 类型)。下表显示了 Rust 中的内置的整数类型: @@ -42,91 +41,36 @@ Rust 使用一个相对传统的语法来创建整数(`1`,`2`,...)和浮 这么多类型,有没有一个简单的使用准则?答案是肯定的, Rust 整形默认使用 `i32`,例如 `let i = 1`,那 `i` 就是 `i32` 类型,因此你可以首选它,同时该类型也往往是性能最好的。`isize` 和 `usize` 的主要应用场景是用作集合的索引。 -> ##### 整型溢出 -> -> 比方说有一个 `u8` ,它可以存放从 0 到 255 的值。那么当你将其修改为范围之外的值,比如 256,则会发生**整型溢出**。关于这一行为 Rust 有一些有趣的规则:当在 debug 模式编译时,Rust 会检查整型溢出,若存在这些问题,则使程序在编译时 _panic_(崩溃,Rust 使用这个术语来表明程序因错误而退出)。 -> -> 在当使用 `--release` 参数进行 release 模式构建时,Rust **不**检测溢出。相反,当检测到整型溢出时,Rust 会按照补码循环溢出(_two’s complement wrapping_)的规则处理。简而言之,大于该类型最大值的数值会被补码转换成该类型能够支持的对应数字的最小值。比如在 `u8` 的情况下,256 变成 0,257 变成 1,依此类推。程序不会 _panic_,但是该变量的值可能不是你期望的值。依赖这种默认行为的代码都应该被认为是错误的代码。 -> -> 要显式处理可能的溢出,可以使用标准库针对原始数字类型提供的这些方法: -> -> - 使用 `wrapping_*` 方法在所有模式下都按照补码循环溢出规则处理,例如 `wrapping_add` -> - 如果使用 `checked_*` 方法时发生溢出,则返回 `None` 值 -> - 使用 `overflowing_*` 方法返回该值和一个指示是否存在溢出的布尔值 -> - 使用 `saturating_*` 方法使值达到最小值或最大值 - -#### 浮点类型 -**浮点类型数字** 是带有小数点的数字,在 Rust 中浮点类型数字也有两种基本类型: `f32` 和 `f64`,分别为 32 位和 64 位大小。默认浮点类型是 `f64`,在现代的 CPU 中它的速度与 `f32` 几乎相同,但精度更高。 - -下面是一个演示浮点数的示例: +#### 整型溢出 -```rust -fn main() { - let x = 2.0; // f64 +假设有一个 `u8` ,它可以存放从 0 到 255 的值。那么当你将其修改为范围之外的值,比如 256,则会发生**整型溢出**。关于这一行为 Rust 有一些有趣的规则:当在 debug 模式编译时,Rust 会检查整型溢出,若存在这些问题,则使程序在编译时 _panic_(崩溃,Rust 使用这个术语来表明程序因错误而退出)。 - let y: f32 = 3.0; // f32 -} -``` - -浮点数根据 `IEEE-754` 标准实现。`f32` 类型是单精度浮点型,`f64` 为双精度。 - -#### 数字运算 - -Rust 支持所有数字类型的基本数学运算:加法、减法、乘法、除法和取模运算。下面代码各使用一条 `let` 语句来说明相应运算的用法: - -```rust -fn main() { - // 加法 - let sum = 5 + 10; - - // 减法 - let difference = 95.5 - 4.3; +在当使用 `--release` 参数进行 release 模式构建时,Rust **不**检测溢出。相反,当检测到整型溢出时,Rust 会按照补码循环溢出(_two’s complement wrapping_)的规则处理。简而言之,大于该类型最大值的数值会被补码转换成该类型能够支持的对应数字的最小值。比如在 `u8` 的情况下,256 变成 0,257 变成 1,依此类推。程序不会 _panic_,但是该变量的值可能不是你期望的值。依赖这种默认行为的代码都应该被认为是错误的代码。 - // 乘法 - let product = 4 * 30; +要显式处理可能的溢出,可以使用标准库针对原始数字类型提供的这些方法: - // 除法 - let quotient = 56.7 / 32.2; +- 使用 `wrapping_*` 方法在所有模式下都按照补码循环溢出规则处理,例如 `wrapping_add` +- 如果使用 `checked_*` 方法时发生溢出,则返回 `None` 值 +- 使用 `overflowing_*` 方法返回该值和一个指示是否存在溢出的布尔值 +- 使用 `saturating_*` 方法使值达到最小值或最大值 - // 求余 - let remainder = 43 % 5; -} -``` +## 浮点类型 -这些语句中的每个表达式都使用了数学运算符,并且计算结果为一个值,然后绑定到一个变量上。[附录 B](https://course.rs/appendix/operators.html#运算符) 中给出了 Rust 提供的所有运算符的列表。 +**浮点类型数字** 是带有小数点的数字,在 Rust 中浮点类型数字也有两种基本类型: `f32` 和 `f64`,分别为 32 位和 64 位大小。默认浮点类型是 `f64`,在现代的 CPU 中它的速度与 `f32` 几乎相同,但精度更高。 -再来看一个综合性的示例: +下面是一个演示浮点数的示例: ```rust fn main() { - // 编译器会进行自动推导,给予twenty i32的类型 - let twenty = 20; - // 类型标注 - let twenty_one: i32 = 21; - // 通过类型后缀的方式进行类型标注:22是i32类型 - let twenty_two = 22i32; - - // 只有同样类型,才能运算 - let addition = twenty + twenty_one + twenty_two; - println!("{} + {} + {} = {}", twenty, twenty_one, twenty_two, addition); - - // 对于较长的数字,可以用_进行分割,提升可读性 - let one_million: i64 = 1_000_000; - println!("{}", one_million.pow(2)); - - // 定义一个f32数组,其中42.0会自动被推导为f32类型 - let forty_twos = [ - 42.0, - 42f32, - 42.0_f32, - ]; + let x = 2.0; // f64 - // 打印数组中第一个值,并控制小数位为2位 - println!("{:.2}", forty_twos[0]); + let y: f32 = 3.0; // f32 } ``` +浮点数根据 `IEEE-754` 标准实现。`f32` 类型是单精度浮点型,`f64` 为双精度。 + #### 浮点数陷阱 浮点数由于底层格式的特殊性,导致了如果在使用浮点数时不够谨慎,就可能造成危险,有两个原因: @@ -200,7 +144,89 @@ note: run with `RUST_BACKTRACE=1` environment variable to display 是不是**blow your mind away**? 没关系,在本书的后续章节中类似的直击灵魂的地方还很多,这就是敢号称 `Rust语言圣经(Rust Course)` 的底气! -#### 位运算 +#### NaN + +对于数学上未定义的结果,例如对负数取平方根 `-42.1.sqrt()` ,会产生一个特殊的结果:Rust 的浮点数类型使用 `NaN` (not a number)来处理这些情况。 + +**所有跟 `NaN` 交互的操作,都会返回一个 `NaN`**,而且 `NaN` 不能用来比较,下面的代码会崩溃: + +```rust +fn main() { + let x = (-42.0_f32).sqrt(); + assert_eq!(x, x); +} +``` + +出于防御性编程的考虑,可以使用 `is_nan()` 等方法,可以用来判断一个数值是否是 `NaN` : + +```rust +fn main() { + let x = (-42.0_f32).sqrt(); + if x.is_nan() { + println!("未定义的数学行为") + } +} +``` + +## 数字运算 + +Rust 支持所有数字类型的基本数学运算:加法、减法、乘法、除法和取模运算。下面代码各使用一条 `let` 语句来说明相应运算的用法: + +```rust +fn main() { + // 加法 + let sum = 5 + 10; + + // 减法 + let difference = 95.5 - 4.3; + + // 乘法 + let product = 4 * 30; + + // 除法 + let quotient = 56.7 / 32.2; + + // 求余 + let remainder = 43 % 5; +} +``` + +这些语句中的每个表达式都使用了数学运算符,并且计算结果为一个值,然后绑定到一个变量上。[附录 B](https://course.rs/appendix/operators.html#运算符) 中给出了 Rust 提供的所有运算符的列表。 + +再来看一个综合性的示例: + +```rust +fn main() { + // 编译器会进行自动推导,给予twenty i32的类型 + let twenty = 20; + // 类型标注 + let twenty_one: i32 = 21; + // 通过类型后缀的方式进行类型标注:22是i32类型 + let twenty_two = 22i32; + + // 只有同样类型,才能运算 + let addition = twenty + twenty_one + twenty_two; + println!("{} + {} + {} = {}", twenty, twenty_one, twenty_two, addition); + + // 对于较长的数字,可以用_进行分割,提升可读性 + let one_million: i64 = 1_000_000; + println!("{}", one_million.pow(2)); + + // 定义一个f32数组,其中42.0会自动被推导为f32类型 + let forty_twos = [ + 42.0, + 42f32, + 42.0_f32, + ]; + + // 打印数组中第一个值,并控制小数位为2位 + println!("{:.2}", forty_twos[0]); +} +``` + + + +## 位运算 Rust的运算基本上和其他语言一样 @@ -241,29 +267,6 @@ fn main() { } ``` -#### NaN - -对于数学上未定义的结果,例如对负数取平方根 `-42.1.sqrt()` ,会产生一个特殊的结果:Rust 的浮点数类型使用 `NaN` (not a number)来处理这些情况。 - -**所有跟 `NaN` 交互的操作,都会返回一个 `NaN`**,而且 `NaN` 不能用来比较,下面的代码会崩溃: - -```rust -fn main() { - let x = (-42.0_f32).sqrt(); - assert_eq!(x, x); -} -``` - -出于防御性编程的考虑,可以使用 `is_nan()` 等方法,可以用来判断一个数值是否是 `NaN` : - -```rust -fn main() { - let x = (-42.0_f32).sqrt(); - if x.is_nan() { - println!("未定义的数学行为") - } -} -``` ## 序列(Range) diff --git a/src/rust-weekly.md b/src/rust-weekly.md index 4aeec07d..e5c2758f 100644 --- a/src/rust-weekly.md +++ b/src/rust-weekly.md @@ -1,16 +1,12 @@ -# Rust 语言周刊 +# 「Rust 语言周刊」 第 8 期 · 2022-04-15 +Rust语言周刊精选全世界过去一周的优秀文章、新闻、开源项目和语言动态。 -精选过去一周的文章、新闻、开源项目和 Rust 语言动态( 中文内容用 🇨🇳 进行标识 ),欢迎大家[订阅及查看往期回顾](https://github.com/studyrs/rust-weekly)。 +本周刊由 Rust 语言中文网倾情打造,其中的 `[Zh]` 标识的中文资料由 Rust 翻译计划提供,并且原始的 Markdown 文档已[全部开源](https://github.com/rustlang-cn/rustt),欢迎大家阅读和订阅。 +> 官方网址:https://cnru.st, 公众号: Rust语言中文网 -## 「Rust 语言周刊」 第 7 期 · 2022-04-08 -Rust 语言周刊精选过去一周的优秀文章、新闻、开源项目和 Rust 语言动态。 - -本周刊由 Rust 语言中文网倾情打造,其中的 [Zh] 中文资料由 Rustt 进行翻译,原始 Markdown 文档已全部开源,欢迎大家阅读和订阅。 - - - -
题图: 一本生锈的书
+ +
题图: 开发 DNS 客户端过程中的笑与泪
#### Rust新闻 @@ -18,65 +14,63 @@ Rust 语言周刊精选过去一周的优秀文章、新闻、开源项目和 Ru 在新版中,我们可以查看 Cargo 构建时的详细耗时了,有助于分析和改善编译时间,还有就是条件编译和依赖引入了新的期待已久的功能。 -1、[Zh] [Rust 2024 官方路线图公布](https://www.163.com/dy/article/H4CMGAF50511CUMI.html) -这篇文章从比较宏观的角度讲解了 Rust 2024 的路线图。 +2、[rust-analyzer 正式加入官方组织](https://www.reddit.com/r/rust/comments/u2nm0y/rustanalyzer_is_now_official_github_repo_moved_to/) + +优秀的产品很难被埋没,`rust-analyzer` 就是如此,这不,现在已经正式成为了官方项目,并且很快会替代 `rls` 成为 VSCode上的默认首选插件,新人有福了。 -2、[Zh] [Rust 2024:敢于要求更多](https://github.com/studyrs/Rustt/blob/main/Articles/%5B2022-03-28%5D%20Rust%202024:敢于要求更多.md) -本文是从更细节的角度出发讲解 Rust 2024 的路线图,喜欢技术细节的同学不容错过。 +#### 精选文章 -3、[Rust 基金会激励计划](https://foundation.rust-lang.org/news/2022-03-31-cgp-is-open-announcement/) +1、[Zh] [Rust 的 unsafe 指针,到底怎么了?](https://github.com/rustlang-cn/Rustt/blob/main/Articles/%5B2022-04-07%5D%20Rust%20的%20unsafe%20指针类型需要大修.md) -基金会筹划已久的开源项目激励计划终于开始实施了,里面包含了基金会合作伙伴、开源项目等一系列举措,大家快去申请了! +本文由 `Nomicon` 和 `Too Many Lists` 作者编写,大佬对 Rust 现有的裸指针进行了深入剖析,并给出了相应的解决方案,干货满满! -#### 开源项目 +2、[Zh] [理解 Rust 的借用检查器](https://github.com/rustlang-cn/Rustt/blob/main/Articles/%5B2022-04-07%5D%20理解%20Rust%20的借用检查器.md) -1、[一本生锈的书](https://github.com/studyrs/rusty-book) +每当你心潮澎湃想要写一些 Rust 代码时,可能最后都会败给借用检查器。 -这本书主要关于如何打造一个 “有锈” 的 Rust 项目。 +3、[Zh] [使用 Rust 构建自己的区块链平台](https://github.com/rustlang-cn/Rustt/blob/main/Articles/%5B2022-04-07%5D%20使用%20Rust%20和%20Substrate%20构建自己的区块链平台.md) -2、[StarfishQL](https://www.sea-ql.org/SeaORM/blog/2022-04-04-introducing-starfish-ql/) +本文将基于著名的 [Substrate](https://substrate.io) 区块链框架来构建一个区块链平台:一个博客后端,用户可以在此提交博客文章、发表评论等。 -一个图数据库和查询引擎,目前主要的目的是绘制和探索 crates.io 上的包依赖网络。 +4、[Zh] [由 Java/C#/C/C++ 开发者转为 Rustacean](https://github.com/rustlang-cn/Rustt/blob/main/Articles/%5B2022-04-02%5D%20由%20Java:C%23:C:C%2B%2B%20开发者转为%20Rustacean.md) -3、[Coppers](https://github.com/ThijsRay/coppers) +从题目能看出,作者是一个爱秀肌肉的多面手,对了,他还在写一本生命周期的书,值得期待! -一套测试工具,用于测量 Rust 项目的能耗情况。 +5、[开发 DNS 客户端过程中的笑与泪](https://blog.adamchalmers.com/making-a-dns-client/) -#### 精选文章 +看看下面这张图,你是否被勾引起开发一个 DNS 客户端的兴趣?反正作者是的。 -1、[虚弱之塔: 每个人都应该懂的内存模型](https://gankra.github.io/blah/tower-of-weakenings/) + -干货作者又出手了,这次为我们带来了内存模型的分析和改进。他甚至基于这种改进修改了 Rust 代码,并且应用在自己的部分项目上,crazy! +6、[生命苦短,我选择与编译检查搏斗?](https://kerkour.com/life-is-short-rust-borrow-checker) -2、[Rust 的 Mutex 为何这样设计?](https://cliffle.com/blog/rust-mutexes/) +本文很短,短到令人震惊,但是确实很好的吐槽了为了对付 Rust 编译检查,我们需要付出的努力。 -已经有不少人抱怨为何 Rust 的 Mutex 跟别的语言不一样,例如它可以持有数据。作者针对这些疑问给出了自己的分析,总之他站队 Rust 的设计。 +7、[默认值和类型推断:使用表达式来替代类型](https://gankra.github.io/blah/defaults-affect-inference/) -3、[Zh] [在 Rust 中使用 epoll 实现非阻塞 IO](https://github.com/studyrs/Rustt/blob/main/Articles/%5B2022-03-29%5D%20在%20Rust%20中使用%20epoll%20实现基本的非阻塞%20IO.md) +你是否注意过 Rust 中的集合类型存在一些奇怪的约束条件?这种奇怪已经存在很久了,甚至在 1.0 版本前就有,本文试图解释下相关的问题并且尝试使用一种新的方法去解决。 -本文试图解释清楚 epoll 和非阻塞 IO 背后的原理 +8、[隐性约束和完美派生](https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/) -4、[Zh] [用 Rust 写 Devops 工具](https://github.com/studyrs/Rustt/blob/main/Articles/%5B2022-04-02%5D%20用%20Rust%20写%20DevOps%20工具.md) +在 Rust 社区中,有两个问题已经被讨论很久了:完美派生以及可扩展的隐性约束,但是最近,Rust 团队在实现它们时遇到了一些问题,一起来看看。 -文章中会介绍几个 Rust 用在 DevOps 领域的案例,以及为什么使用 Rust。其中我们还会介绍一些在 AWS 上基于 Rust 的 DevOps 工具常用的库。 -5、[Zh] [Rust 背后不是公司](https://github.com/studyrs/Rustt/blob/main/Articles/%5B2022-04-01%5D%20Rust%20背后并不是公司.md) -Rust 大佬带来的对 Rust 组织架构的分析。 +9、[系列] [指针很复杂 III](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html) -6、[使用 Rust 改善 Python S3 客户端的性能](https://joshua-robinson.medium.com/improving-python-s3-client-performance-with-rust-e9639359072f) +作者目前的工作需要处理 Rust/MIR 的内存模型,因此会触及到普通开发不太熟悉的领域,系列的文章第一篇见[这里](https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html)。 -Python 是数据科学的主力军语言,但是性能有的时候会成为平静下来。例如现在亚马逊 S3 存储非常火热,如果大家使用 S3 作为数据集的存储,那么 Pyhton 去读取这些数据可能就是一个很大的性能瓶颈。 +10、[使用 Rust 构建爬虫](https://kerkour.com/rust-crawler-associated-types) -7、[Qiskit 使用 Rust 来获取更好的性能](https://medium.com/qiskit/new-weve-started-using-rust-in-qiskit-for-better-performance-a3676433ca8c) +本文节选自 `Black Hat Rust`,在文中,作者清晰的解释了 `scraper` 和 `crawler` 的区别,以及介绍了 Rust 为何非常适合爬虫的原因。 -Qiskit 是一家从事量子计算的公司,最近他们 在 Python 之外还引入了 Rust 语言,事实证明,这个举措带来了显著的性能提升。 -8、[ScyllaDB 将数据库驱动使用异步 Rust 重新实现](https://thenewstack.io/why-were-porting-our-database-drivers-to-async-rust/) +#### 开源项目 -ScyllaDB 是这几年很火的开源分布式 KV 数据库,兼容 Cassandra 的 CQL 协议,性能非常非常高。这不,为了性能和安全性,他们又出手了,这次是使用 Rust 将客户端的驱动进行了重写( 使用 tokio )。 +1、[fdb - 基于 Tokio 的 FoundationDB 客户端驱动](https://github.com/fdb-rs/fdb) -9、[在 2022 年使用 axum 和 yew 打造一个全栈 Rust web 服务](https://robert.kra.hn/posts/2022-04-03_rust-web-wasm/) +FoundationDB 于数年前被苹果收购,并且服务于生产环境多年,是一个非常可靠、非常非常有特色的分布式数据库。 -在过去两年,WebAssembly 在 Rust 这里发展的非常快,而且构建和打包也变得更加简单。因此,是时候使用 Rust 写一套前后端服务了。 +2、[ogma - 用于处理表格化数据的脚本语言](https://github.com/kdr-aus/ogma) + diff --git a/内容变更记录.md b/内容变更记录.md index d02646eb..c5ae59a5 100644 --- a/内容变更记录.md +++ b/内容变更记录.md @@ -1,6 +1,10 @@ # ChangeLog 记录一些值得注意的变更。 +## 2022-04-15 + +- 调整数值类型章节的目录结构,并新增位运算,感谢 [liCells](https://github.com/liCells) 提交的 PR + ## 2022-04-12 - [优化字符串章节,增加字符串转义](https://course.rs/basic/compound-type/string-slice.html#字符串转义)