[提交翻译][tech]: 20230410.0 ️ Rust Basics Series 3 Data Types in Rust (#29363)

* [翻译完成][tech]: 20230410.0 ️ Rust Basics Series 3 Data Types in Rust

* [移动翻译][tech]: 20230410.0 ️ Rust Basics Series 3 Data Types in Rust

* [FIX][tech]: 20230410.0 ️ Rust Basics Series 3 Data Types in Rust
This commit is contained in:
Qian Qian "Cubik"‎ 2023-05-11 11:09:27 -04:00 committed by GitHub
parent 03f38648dd
commit 478fa7deda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 232 additions and 233 deletions

View File

@ -1,233 +0,0 @@
[#]: subject: "Rust Basics Series #3: Data Types in Rust"
[#]: via: "https://itsfoss.com/rust-data-types/"
[#]: author: "Pratham Patel https://itsfoss.com/author/pratham/"
[#]: collector: "lkxed"
[#]: translator: "Cubik65536"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
Rust Basics Series #3: Data Types in Rust
======
![][1]
In the [previous post][2] about the Rust programming language, we looked at variables, constants and shadowing.
It is only natural to cover data types now.
### What are data types?
Change the order of these words and you get your answer; "data types" -> "type of data".
The computer stores data as `0`s and `1`s but to make sense of it when reading, we use data type to say what those `0`s and `1`s mean.
Rust has two types of data types:
- **Scalar data type**: Types that store only a single value.
- **Compound data type**: Types that store multiple values, even values of different types.
In this article, I shall cover scalar data types. I will go through the second category in the next article.
Following is a brief overview of the four main categories of Scalar data types in Rust:
- **Integers**: Stores whole numbers. Has sub-types for each specific use case.
- **Floats**: Stores numbers with a fractional value. Has two sub-types based on size.
- **Characters**: Stores a single character of UTF-8 encoding. (Yes, you can store an emoji* in a character.)
- **Booleans**: Stores either a `true` or a `false`. (For developers who can't agree if `0` is `true` or if `0` means `false`.)
### Integers
An integer in the context of a programming language refers to whole numbers. Integers in Rust are either **Signed** or **Unsigned**. Unsigned integers store only 0 and positive numbers, while Signed integers can store negative numbers, 0 and positive numbers.
> 💡 The range of Signed integers begins from `-(2n-1)` and this range ends with `(2n-1)-1`. Likewise, the range for Unsigned integers starts at `0` and ends with `(2n)-1`.
Following are the available Integer types based on the sign and length:
![Integer data types in Rust][3]
As you can see, Rust has Signed and Unsigned integers of length 8, 16, 32, 64 and even 128!
The integers with `*size` vary based on the architecture of the computer. On 8-bit micro-controllers, it is `*8`, on 32-bit legacy computers, it is `*32` and on modern 64-bit systems, it is `*64`.
The use of `*size` is to store data that is mostly related to memory (which is machine dependent), like pointers, offsets, etc.
> 💡 When you do not explicitly specify a subset of the Integer type, the Rust compiler will infer it's type to be `i32` by default. Obviously, if the value is bigger or smaller than what `i32` can hold, the Rust compiler will politely error out and ask you to manually annotate the type.
Rust not only allows you to store integers in their decimal form but also in the binary, octal and hex forms too.
For better readability, you can use underscore `_` as a replacement for commas in writing/reading big numbers.
```
fn main() {
let bin_value = 0b100_0101; // use prefix '0b' for Binary representation
let oct_value = 0o105; // use prefix '0o' for Octals
let hex_value = 0x45; // use prefix '0x' for Hexadecimals
let dec_value = 1_00_00_000; // same as writing 1 Crore (1,00,00,000)
println!("bin_value: {bin_value}");
println!("oct_value: {oct_value}");
println!("hex_value: {hex_value}");
println!("dec_value: {dec_value}");
}
```
I have stored the decimal number 69 in binary form, octal form and hexadecimal form in the variables `bin_value`, `oct_value` and `hex_value` respectively. In the variable `dec_value`, I have stored the number [1 Crore][4] (10 million) and have commas with underscores, as per the Indian numbering system. For those more familiar with the International numbering system, you may write this as `10_000_000`.
Upon compiling and running this binary, I get the following output:
```
bin_value: 69
oct_value: 69
hex_value: 69
dec_value: 10000000
```
### Floating point numbers
Floating point numbers, or more commonly known as "float(s)" is a data type that holds numbers that have a fractional value (something after the decimal point).
Unlike the Integer type in Rust, Floating point numbers have only two subset types:
- `f32`: Single precision floating point type
- `f64`: Double precision floating point type
Like the Integer type in Rust, when Rust infers the type of a variable that seems like a float, it is assigned the `f64` type. This is because the `f64` type has more precision than the `f32` type and is almost as fast as the `f32` type in most computational operations. Please note that _both the floating point data types (`f32` and `f64`) are **Signed**_.
> 📋 The Rust programming language stores the floating point numbers as per the [IEEE 754][5] standard of floating point number representation and arithmetic.
```
fn main() {
let pi: f32 = 3.1400; // f32
let golden_ratio = 1.610000; // f64
let five = 5.00; // decimal point indicates that it must be inferred as a float
let six: f64 = 6.; // even the though type is annotated, a decimal point is still
// **necessary**
println!("pi: {pi}");
println!("golden_ratio: {golden_ratio}");
println!("five: {five}");
println!("six: {six}");
}
```
Look closely at the 5th line. Even though I have annotated the type for the variable `six`, I **need** to at least use the decimal point. If you have something _after_ the decimal point is up to you.
The output of this program is pretty predictable... Or is it?
```
pi: 3.14
golden_ratio: 1.61
five: 5
six: 6
```
In the above output, you might have noticed that while displaying the value stored inside variables `pi`, `golden_ratio` and `five`, the trailing zeros that I specified at the time of variable declaration, are missing.
While those zeros are not _removed_, they are omitted while outputting the values via the `println` macro. So no, Rust did not tamper with your variable's values.
### Characters
You can store a single character in a variable and the type is simply `char`. Like traditional programming languages of the '80s, you can store an [ASCII][6] character. But Rust also extends the character type to store a valid UTF-8 character. This means that you can store an emoji in a single character 😉
> 💡 Some emojis are a mix of two existing emojis. A good example is the 'Fiery Heart' emoji: ❤️‍🔥. This emoji is constructed by combining two emojis using a [zero width joiner][7]: ❤️ + 🔥 = ❤️‍🔥
>
> Storing such emojis in a single Rust variable of the character type is not possible.
```
fn main() {
let a = 'a';
let p: char = 'p'; // with explicit type annotation
let crab = '🦀';
println!("Oh look, {} {}! :{}", a, crab, p);
}
```
As you can see, I have stored the ASCII characters 'a' and 'p' inside variables `a` and `p`. I also store a valid UTF-8 character, the crab emoji, in the variable `crab`. I then print the characters stored in each of these variables.
Following is the output:
```
Oh look, a 🦀! :p
```
### Booleans
The boolean type in Rust stores only one of two possible values: either `true` or `false`. If you wish to annotate the type, use `bool` to indicate the type.
```
fn main() {
let val_t: bool = true;
let val_f = false;
println!("val_t: {val_t}");
println!("val_f: {val_f}");
}
```
The above code, when compiled and executed results in the following output:
```
val_t: true
val_f: false
```
### Bonus: Explicit typecasting
In the previous article about Variables in the Rust programming language, I showed a very basic [temperature conversion program][8]. In there, I mentioned that Rust does not allow implicit typecasting.
But that doesn't mean that Rust does not allow _explicit_ typecasting either ;)
To perform explicit type casting, the `as` keyword is used and followed by the data type to which the value should be cast in.
Following is a demo program:
```
fn main() {
let a = 3 as f64; // f64
let b = 3.14159265359 as i32; // i32
println!("a: {a}");
println!("b: {b}");
}
```
On line 2, instead of using '3.0', I follow the '3' with `as f64` to denote that I want the compiler to handle type casting of '3' (an Integer) into a 64-bit float. Same with the 3rd line. But here, the type casting is **lossy**. Meaning, that the fractional element is _completely gone_. Instead of storing `3.14159265359`, it is stored as simply `3`.
This can be verified from the program's output:
```
a: 3
b: 3
```
### Conclusion
This article covers the Primitive/Scalar data types in Rust. There are primarily four such data types: Integers, Floating point numbers, Characters and Booleans.
Integers are used to store whole numbers and they have several sub-types based on either they are signed or unsigned and the length. Floating point numbers are used to store numbers with some fractional values and have two sub-types based on length. The character data type is used to store a single, valid UTF-8 encoded character. Finally, booleans are used to store either a `true` or `false` value.
In the next chapter, I'll discuss compound data types like arrays and tuples. Stay tuned.
--------------------------------------------------------------------------------
via: https://itsfoss.com/rust-data-types/
作者:[Pratham Patel][a]
选题:[lkxed][b]
译者:[Cubik65536](https://github.com/Cubik65536)
校对:[Cubik65536](https://github.com/Cubik65536)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/pratham/
[b]: https://github.com/lkxed/
[1]: https://itsfoss.com/content/images/2023/04/humble-bundle-packt-offer.webp
[2]: https://itsfoss.com/rust-variables
[3]: https://media.discordapp.net/attachments/1001332168506753024/1062952929734164540/data-type-table1.png
[4]: https://en.wikipedia.org/wiki/Crore?ref=itsfoss.com
[5]: https://en.wikipedia.org/wiki/IEEE_754?ref=itsfoss.com
[6]: https://www.ascii-code.com/?ref=itsfoss.com
[7]: https://unicode-table.com/en/200D/?ref=itsfoss.com
[8]: https://itsfoss.com/rust-variables/#a-rusty-thermometer

View File

@ -0,0 +1,232 @@
[#]: subject: "Rust Basics Series #3: Data Types in Rust"
[#]: via: "https://itsfoss.com/rust-data-types/"
[#]: author: "Pratham Patel https://itsfoss.com/author/pratham/"
[#]: collector: "lkxed"
[#]: translator: "Cubik65536"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
Rust 基础系列 #3: Rust 中的数据类型
======
![][1]
在 [上一篇](https://linux.cn/article-15771-1.html) 关于 Rust 编程语言的文章中,我们提到了变量、常量和 <ruby>遮蔽<rt>shadowing</rt></ruby>
现在来讲解数据类型是再自然不过的了。
### 数据类型是什么?
将这些单词的顺序改变一下你就会得到答案了;“数据类型” -> “数据的类型”。
计算机使用 `0``1` 来存储数据,但是为了让数据在读取时有意义,我们使用数据类型来表示这些 `0``1` 的含义。
Rust 有两种数据类型:
- **标量数据类型**:只能存储单个值的类型。
- **复合数据类型**:可以存储多个值,甚至是不同类型的值。
在本文中,我将讲解标量数据类型。我将在下一篇文章中讲解第二类数据类型。
接下来是 Rust 中四种主要标量数据类型的简要概述:
- **整数**:存储整数。有每种特定情况下使用的子类型。
- **浮点数**:存储带有小数部分的数字。有两种基于大小的子类型。
- **字符**:使用 UTF-8 编码存储单个字符。(是的,你可以在字符中存储表情符号*。)
- **布尔值** 存储 `true``false`。(给那些无法就 `0``true` 还是 `0``false` 达成一致的开发者。)
### 整型
在编程语言中整型指的是一个整数。Rust 中的整型要么是**有符号**的,要么是**无符号**的。无符号整型只能存储 0 和正数而有符号整型可以存储负数、0 和正数。
> 💡 一个有符号整型的范围从 <code>-(2<sup>n-1</sup>)</code> 开始,以 <code>(2<sup>n-1</sup>)-1</code> 结束。同样,无符号整型的范围从 `0` 开始,以 <code>(2<sup>n</sup>)-1</code> 结束。
这是根据符号和长度可用的整型:
![Rust 中的整型数据类型][3]
正如你所见Rust 有 8、16、32、64 甚至 128 位的有符号和无符号整型!
使用 `*size` 的整型根据计算机的架构而变化。在 8 位微控制器上,它是 `*8`,在 32 位的旧计算机上,它是 `*32`,在现代 64 位系统上,它是 `*64`
使用 `*size` 是为了存储与内存(这与裸机相关)有关的数据,比如指针、偏移量等。
> 💡 当你没有显式地指定整型的子类型时Rust 编译器会默认推断为 `i32`。显然,如果值比 `i32` 能存储的值大或小Rust 编译器会礼貌地报错并要求你手动指定类型。
Rust 不仅允许你以十进制形式存储整数,还允许你以二进制、八进制和十六进制形式存储整数。
为了更好的可读性,你可以使用下划线 `_` 来代替逗号来书写/读取大数。
```
fn main() {
let bin_value = 0b100_0101; // 使用前缀“0b”表示二进制
let oct_value = 0o105; // 使用前缀“0o”表示八进制
let hex_value = 0x45; // 使用前缀“0x”表示十六进制
let dec_value = 1_00_00_000; // 跟写一克若 (1,00,00,000) 一样
println!("二进制值: {bin_value}");
println!("八进制值: {oct_value}");
println!("十六进制值: {hex_value}");
println!("十进制值: {dec_value}");
}
```
我使用二进制、八进制和十六进制分别将十进制数 69 存储在变量 `bin_value`、`oct_value` 和 `hex_value` 中。在变量 `dec_value` 中,我存储了数字 [1 克若][4](一千万),并且使用了下划线替代逗号,这是印度的书写系统。对于那些更熟悉国际计数系统的人来说,你可以将其写成 `10_000_000`
在编译并运行这个二进制文件后,我得到了如下输出:
```
二进制值: 69
八进制值: 69
十六进制值: 69
十进制值: 10000000
```
### 浮点数
浮点数是一种存储带有小数部分的数字的数据类型。
与 Rust 中的整型不同,浮点数只有两种子类型:
- `f32`: 单精度浮点数类型
- `f64`: 双精度浮点数类型
和 Rust 中的整型一样,当 Rust 推断一个变量的类型时,如果它看起来像一个浮点数,那么它就会被赋予 `f64` 类型。这是因为 `f64` 类型比 `f32` 类型有更高的精度,并且在大多数计算操作中几乎和 `f32` 类型一样快。请注意_浮点数据类型`f32` 和 `f64`)都是**有符号**的_。
> 📋 Rust 编程语言按照 [IEEE 754][5] 二进制浮点数表示与算术标准存储浮点数。
```
fn main() {
let pi: f32 = 3.1400; // f32
let golden_ratio = 1.610000; // f64
let five = 5.00; // 小数点表示它必须被推断为浮点数
let six: f64 = 6.; // 尽管类型说明被显式的添加了,小数点也是**必须**的
println!("pi: {pi}");
println!("黄金比例: {golden_ratio}");
println!("五: {five}");
println!("六: {six}");
}
```
仔细看第 5 行。尽管我已经为变量 `six` 指定了类型,但我**必须**至少加上一个小数点。小数点之后有什么就由你决定了。
程序的输出是相当可预测的... 吗?
```
pi: 3.14
黄金比例: 1.61
五: 5
六: 6
```
在上面的输出中,你可能已经注意到,当显示变量 `pi`、`golden_ratio` 和 `five` 中存储的值时,我在变量声明时在结尾增加的零已经消失了。
就算这些零没有被 _移除_,它们也会在通过 `println` 宏输出值时被省略。所以Rust 没有篡改你的变量值。
### 字符
你可以在一个变量中存储一个字符,类型是 `char`。像 80 年代的传统编程语言一样,你可以存储一个 [ASCII][6] 字符。但是 Rust 还扩展了字符类型,以存储一个有效的 UTF-8 字符。这意味着你可以在一个字符中存储一个表情符号 😉
> 💡 一些表情符号实际上是两个已有表情符号的组合。一个很好的例子是“燃烧的心”表情符号:❤️‍🔥。这个表情符号是通过使用 [零宽度连接器][7] 来组合两个表情符号构成的:❤️ + 🔥 = ❤️‍🔥
>
> Rust 的字符类型无法存储这样的表情符号。
```
fn main() {
let a = 'a';
let p: char = 'p'; // 带有显性类型说明
let crab = '🦀';
println!("Oh look, {} {}! :{}", a, crab, p);
}
```
正如你所见,我已经将 ASCII 字符 'a' 和 'p' 存储在变量 `a``p` 中。我还在变量 `crab` 中存储了一个有效的 UTF-8 字符,即螃蟹表情符号。然后我打印了存储在每个变量中的字符。
这是输出:
```
Oh look, a 🦀! :p
```
### 布尔值
在 Rust 中,布尔值类型只存储两个可能的值之一:`true` 或 `false`。如果你想显性指定类型,请使用 `bool`
```
fn main() {
let val_t: bool = true;
let val_f = false;
println!("val_t: {val_t}");
println!("val_f: {val_f}");
}
```
编译并执行上述代码后,结果如下:
```
val_t: true
val_f: false
```
### 额外内容:显性类型转换
在上一篇讲述 Rust 编程语言中的变量的文章中,我展示了一个非常基础的[温度转换程序][8]。在那里,我提到 Rust 不允许隐式类型转换。
但这不代表 Rust 也不允许 _显性_ 类型转换 ;)
要进行显性类型转换,使用 `as` 关键字,后面跟着要转换的数据类型。
这是一个示例程序:
```
fn main() {
let a = 3 as f64; // f64
let b = 3.14159265359 as i32; // i32
println!("a: {a}");
println!("b: {b}");
}
```
在第二行,我没有使用 '3.0',而是在 '3' 后面写上 `as f64`,以表示我希望编译器将 '3'(一个整数)转换为 64 位浮点数的类型转换。第三行也是一样。但是这里,类型转换是**有损的**。这意味着小数部分 _完全消失_。它不是存储为 `3.14159265359`,而是存储为简单的 `3`
程序的输出可以验证这一点:
```
a: 3
b: 3
```
### 总结
本文介绍了 Rust 中的原始/标量数据类型。主要有四种这样的数据类型:整数、浮点数、字符和布尔值。
整型用于存储整数,它们有几种子类型,基于它们是有符号还是无符号以及长度。浮点数用于存储带有小数的数字,根据长度有两种子类型。字符数据类型用于存储单个有效的 UTF-8 编码字符。最后,布尔值用于存储 `true``false` 值。
在下一章中,我将讨论数组和元组等复合数据类型。敬请关注。
--------------------------------------------------------------------------------
via: https://itsfoss.com/rust-data-types/
作者:[Pratham Patel][a]
选题:[lkxed][b]
译者:[Cubik65536](https://github.com/Cubik65536)
校对:[Cubik65536](https://github.com/Cubik65536)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/pratham/
[b]: https://github.com/lkxed/
[1]: https://itsfoss.com/content/images/2023/04/humble-bundle-packt-offer.webp
[2]: https://itsfoss.com/rust-variables
[3]: https://media.discordapp.net/attachments/1001332168506753024/1062952929734164540/data-type-table1.png
[4]: https://zh.wikipedia.org/zh-cn/克若
[5]: https://zh.wikipedia.org/zh-cn/IEEE_754
[6]: https://www.ascii-code.com/?ref=itsfoss.com
[7]: https://unicode-table.com/en/200D/?ref=itsfoss.com
[8]: https://linux.cn/article-15771-1.html