3.2.0. Before We Begin
Welcome to Chapter 3 of this Rust self-study series. It has 6 sections:
- Variables and Mutability
- Data Types: Scalar Types (this article)
- Data Types: Compound Types
- Functions and Comments
- Control Flow:
if else - Control Flow: Loops
Through the guessing game in Chapter 2 (beginners who have not read it are strongly encouraged to take a look), you should now have learned the basic Rust syntax. In Chapter 3, we will go one level deeper and learn the general programming concepts in Rust.
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
3.2.1. Variable Characteristics in Rust
Rust is a statically compiled language, so the compiler must know the type of every variable at compile time.
- Based on how a value is used, the compiler can usually infer its exact type.
- If there are too many possible types, you must add a type annotation, otherwise compilation will fail. Here is an example:
let guess = "6657".parse().expect("Please enter a number");
If you put this line into an IDE, you will see an error such as type error: type annotations needed. That is because the string 6657 could be parsed into types such as i32 or u32, and the compiler does not know which one you want, so you need to explicitly annotate the type. Changing the code to the following will make it compile:
let guess: u32 = "6657".parse().expect("Please enter a number");
3.2.2. An Introduction to Scalar Types
- A scalar type represents a single value.
- Rust mainly has four scalar types:
- Integer types
- Floating-point types
- Boolean types
- Character types
3.2.3. Integer Types
- Unsigned integer types, which cannot represent negative numbers, start with
u;uis short for unsigned. - Signed integer types, which can represent negative numbers, start with
i;iis short for integer. - The number after the letter indicates how many bits the type occupies. For example,
32inu32means it uses 32 bits and can represent values from0to2^32 - 1. - The list of Rust integer types is shown below:
- Each type comes in both
ianduvariants, with fixed bit widths. - Signed range:
-(2^(n-1))to2^(n-1) - 1 - Unsigned range:
0to2^n - 1
- Each type comes in both
| Length | Signed | Unsigned |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| 128-bit | i128 | u128 |
| arch | isize | usize |
The isize and usize types are special integer types whose size depends on the computer architecture on which the program is running:
- On a 64-bit machine, they are 64 bits.
isizeis equivalent toi64, andusizeis equivalent tou64. - On a 32-bit machine, they are 32 bits.
isizeis equivalent toi32, andusizeis equivalent tou32.
The main use case for isize and usize is indexing collections.
fn main(){
let machine: u32 = 6657;
}
3.2.4. Integer Literals
Integers are not limited to decimal notation; other bases are also supported. Using fixed formats lets the program understand the base you intended and also makes your code easier for other people to read.
| Number literals | Example |
|---|---|
| Decimal | 98_222 |
| Hex | 0xff |
| Octal | 0o77 |
| Binary | 0b1111_0000 |
| Byte (u8 only) | b'A' |
- Underscores can be added to decimal numbers to improve readability.
- Hexadecimal numbers start with
0x. - Octal numbers start with
0o. - Binary numbers start with
0b, and underscores can also be added to improve readability. - Byte literals are a special case. In Rust, a byte integer literal is written as
b'X', whereXis a single character representing a byte value. This literal can only be used withu8, because a byte value ranges from 0 to 255, andXmust be an ASCII character. For example,b'A'has the value 65 because the ASCII code forAis 65. - Aside from byte literals, all numeric literals may use a type suffix.
- If you are not sure which type to use, you can rely on Rust's corresponding default type.
- The default integer type is
i32, which is generally very fast even on 64-bit systems.
3.2.5. Integer Overflow
For example, the range of u8 is 0 to 255. If you set the value of a u8 variable to 256, two things can happen:
- In debug builds, Rust checks for overflow. If overflow occurs, the program panics at runtime.
- In release builds (
--release), Rust does not check for overflow that could lead to panic.- If overflow does occur, Rust performs wrapping arithmetic: 256 becomes 0, 257 becomes 1, and so on, but it does not panic.
3.2.6. Floating-Point Types
Rust has two basic floating-point types:
-
f32: 32-bit single precision -
f64: 64-bit double precision
Rust uses the IEEE-754 standard to represent floating-point types.
f64 is the default type because on modern CPUs, f64 runs about as fast as f32, and f64 is more precise.
fn main(){
let machine: f32 = 6657.0721;
}
3.2.7. Numeric Operations
- Add:
+ - Subtract:
- - Multiply:
* - Divide:
/ - Remainder:
%These are no different from other languages.
3.2.8. Boolean Types
Rust's boolean type is no different from that of other languages. It has two values: true and false, occupies one byte, and the keyword is bool.
fn main(){
let machine: bool = true;
}
3.2.9. Character Types
- Rust's
chartype is used to represent the most basic single characters in a language. - Character literals use single quotes.
- It occupies 4 bytes.
- It is a Unicode scalar value, so it can represent far more than ASCII, including pinyin, Chinese, Japanese, and Korean characters, zero-width characters, emojis, and more. Its range is from
U+0000toU+D7FFand fromU+E000toU+10FFFF. - Unicode does not actually have a concept of a "character" in the way we usually think about it, so the characters we intuitively recognize may not line up exactly with Rust's concept.
fn main(){
let x: char = '🥵';
}
Top comments (0)