DEV Community

Cover image for [Rust Guide] 3.2. Data Types - Scalar Types
SomeB1oody
SomeB1oody

Posted on

[Rust Guide] 3.2. Data Types - Scalar Types

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");
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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; u is short for unsigned.
  • Signed integer types, which can represent negative numbers, start with i; i is short for integer.
  • The number after the letter indicates how many bits the type occupies. For example, 32 in u32 means it uses 32 bits and can represent values from 0 to 2^32 - 1.
  • The list of Rust integer types is shown below:
    • Each type comes in both i and u variants, with fixed bit widths.
    • Signed range: -(2^(n-1)) to 2^(n-1) - 1
    • Unsigned range: 0 to 2^n - 1
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. isize is equivalent to i64, and usize is equivalent to u64.
  • On a 32-bit machine, they are 32 bits. isize is equivalent to i32, and usize is equivalent to u32.

The main use case for isize and usize is indexing collections.

fn main(){
    let machine: u32 = 6657;
}
Enter fullscreen mode Exit fullscreen mode

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', where X is a single character representing a byte value. This literal can only be used with u8, because a byte value ranges from 0 to 255, and X must be an ASCII character. For example, b'A' has the value 65 because the ASCII code for A is 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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

3.2.9. Character Types

  • Rust's char type 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+0000 to U+D7FF and from U+E000 to U+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 = '🥵';
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)