100 exercises to learn Rust
This commit is contained in:
138
book/src/02_basic_calculator/01_integers.md
Normal file
138
book/src/02_basic_calculator/01_integers.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Types, part 1
|
||||
|
||||
In the ["Syntax" section](../01_intro/01_syntax.md) `compute`'s input parameters were of type `u32`.
|
||||
Let's unpack what that _means_.
|
||||
|
||||
## Primitive types
|
||||
|
||||
`u32` is one of Rust's **primitive types**. Primitive types are the most basic building blocks of a language.
|
||||
They're built into the language itself—i.e. they are not defined in terms of other types.
|
||||
|
||||
You can combine these primitive types to create more complex types. We'll see how soon enough.
|
||||
|
||||
## Integers
|
||||
|
||||
`u32`, in particular, is an **unsigned 32-bit integer**.
|
||||
|
||||
An integer is a number that can be written without a fractional component. E.g. `1` is an integer, while `1.2` is not.
|
||||
|
||||
### Signed vs. unsigned
|
||||
|
||||
An integer can be **signed** or **unsigned**.
|
||||
An unsigned integer can only represent non-negative numbers (i.e. `0` or greater).
|
||||
A signed integer can represent both positive and negative numbers (e.g. `-1`, `12`, etc.).
|
||||
|
||||
The `u` in `u32` stands for **unsigned**.
|
||||
The equivalent type for signed integer is `i32`, where the `i` stands for integer (i.e. any integer, positive or
|
||||
negative).
|
||||
|
||||
### Bit width
|
||||
|
||||
The `32` in `u32` refers to the **number of bits[^bit]** used to represent the number in memory.
|
||||
The more bits, the larger the range of numbers that can be represented.
|
||||
|
||||
Rust supports multiple bit widths for integers: `8`, `16`, `32`, `64`, `128`.
|
||||
|
||||
With 32 bits, `u32` can represent numbers from `0` to `2^32 - 1` (a.k.a. [`u32::MAX`](https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.MAX)).
|
||||
With the same number of bits, a signed integer (`i32`) can represent numbers from `-2^31` to `2^31 - 1`
|
||||
(i.e. from [`i32::MIN`](https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MIN)
|
||||
to [`i32::MAX`](https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MAX)).
|
||||
The maximum value for `i32` is smaller than the maximum value for `u32` because one bit is used to represent
|
||||
the sign of the number. Check out the [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement)
|
||||
representation for more details on how signed integers are represented in memory.
|
||||
|
||||
### Summary
|
||||
|
||||
Combining the two variables (signed/unsigned and bit width), we get the following integer types:
|
||||
|
||||
| Bit width | Signed | Unsigned |
|
||||
|-----------|--------|----------|
|
||||
| 8-bit | `i8` | `u8` |
|
||||
| 16-bit | `i16` | `u16` |
|
||||
| 32-bit | `i32` | `u32` |
|
||||
| 64-bit | `i64` | `u64` |
|
||||
| 128-bit | `i128` | `u128` |
|
||||
|
||||
## Literals
|
||||
|
||||
A **literal** is a notation for representing a fixed value in source code.
|
||||
For example, `42` is a Rust literal for the number forty-two.
|
||||
|
||||
### Type annotations for literals
|
||||
|
||||
But all values in Rust have a type, so... what's the type of `42`?
|
||||
|
||||
The Rust compiler will try to infer the type of a literal based on how it's used.
|
||||
If you don't provide any context, the compiler will default to `i32` for integer literals.
|
||||
If you want to use a different type, you can add the desired integer type as a suffix—e.g. `2u64` is a 2 that's
|
||||
explicitly typed as a `u64`.
|
||||
|
||||
### Underscores in literals
|
||||
|
||||
You can use underscores `_` to improve the readability of large numbers.
|
||||
For example, `1_000_000` is the same as `1000000`.
|
||||
|
||||
## Arithmetic operators
|
||||
|
||||
Rust supports the following arithmetic operators[^traits] for integers:
|
||||
|
||||
- `+` for addition
|
||||
- `-` for subtraction
|
||||
- `*` for multiplication
|
||||
- `/` for division
|
||||
- `%` for remainder
|
||||
|
||||
Precedence and associativity rules for these operators are the same as in mathematics.
|
||||
You can use parentheses to override the default precedence. E.g. `2 * (3 + 4)`.
|
||||
|
||||
> ⚠️ **Warning**
|
||||
>
|
||||
> The division operator `/` performs integer division when used with integer types.
|
||||
> I.e. the result is truncated towards zero. For example, `5 / 2` is `2`, not `2.5`.
|
||||
|
||||
## No automatic type coercion
|
||||
|
||||
As we discussed in the previous exercise, Rust is a statically typed language.
|
||||
In particular, Rust is quite strict about type coercion. It won't automatically convert a value from one type to
|
||||
another[^coercion],
|
||||
even if the conversion is lossless. You have to do it explicitly.
|
||||
|
||||
For example, you can't assign a `u8` value to a variable with type `u32`, even though all `u8` values are valid `u32`
|
||||
values:
|
||||
|
||||
```rust
|
||||
let b: u8 = 100;
|
||||
let a: u32 = b;
|
||||
```
|
||||
|
||||
It'll throw a compilation error:
|
||||
|
||||
```text
|
||||
error[E0308]: mismatched types
|
||||
|
|
||||
3 | let a: u32 = b;
|
||||
| --- ^ expected `u32`, found `u8`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
```
|
||||
|
||||
We'll see how to convert between types [later in this course](../04_traits/08_from).
|
||||
|
||||
## References
|
||||
|
||||
- The exercise for this section is located in `exercises/02_basic_calculator/01_integers`
|
||||
|
||||
## Further reading
|
||||
|
||||
- [The integer types section](https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-types) in the official Rust book
|
||||
|
||||
[^bit]: A bit is the smallest unit of data in a computer. It can only have two values: `0` or `1`.
|
||||
|
||||
[^traits]: Rust doesn't let you define custom operators, but it puts you in control of how the built-in operators
|
||||
behave.
|
||||
We'll talk about operator overloading [later in the course](../04_traits/03_operator_overloading), after we've covered traits.
|
||||
|
||||
[^coercion]: There are some exceptions to this rule, mostly related to references, smart pointers and ergonomics. We'll
|
||||
cover those [later on](../04_traits/06_deref).
|
||||
A mental model of "all conversions are explicit" will serve you well in the meantime.
|
||||
Reference in New Issue
Block a user