SoFunction
Updated on 2025-04-11

Rust data type detailed explanation

1. Scalar Types

The scalar type represents a separate value. There are four basic scalar types in Rust:Integer(integer)、Floating point number(floating-point number)、Boole(boolean) andcharacter(character). These types are common in most programming languages.

1. Integer Types

An integer is a number without a fractional part. In the previous tutorial on guessing numbers, we used itu32. This type declaration means that the value is aUnsigned(unsigned) 32-bit integer (if it is signed, it williBeginning, e.g.i32)。

The following table shows all built-in integer types in Rust, each type is either signed or unsigned, and has a clear bit size.

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
  • Signed(signed) means that the value may be positive or negative, so the sign bit is required when storing;
  • Unsigned(unsigned) only represents non-negative numbers (0 or positive numbers) and does not require sign bits.

For signed integers, if the type isi8, it can store values ​​from -128 to 127; if soi16, the scope will be expanded accordingly, and so on. Unsigned types start from 0. For exampleu8Can represent 0 to 255.

isizeandusizeVaries depending on the system architecture: 64-bit on a 64-bit architecture and 32-bit on a 32-bit architecture. These types are often used in scenarios such as indexing or memory size calculation based on the system architecture.

1.1 Overall digital surface volume

In Rust, various forms can be used to express integer literals, as shown in the following table:

Number literal form Example
Decimal 98_222
hexadecimal 0xff
Octal 0o77
Binary 0b1111_0000
Bytes (onlyu8 b'A'

Notice:

  • Underlines can be used in numbers_As a separator to improve readability, e.g.1_000and1000equivalence.
  • If you need to specify a type, you can add a type suffix to the number, for example57u8

Usually if you are not sure what type of integer to use,Rust is used by defaulti32. If you need to index the system architecture and other scenarios, you will only consider using it.isizeorusize

1.2 Integer Overflow

Suppose we have oneu8A variable of type, the range of values ​​it can represent is[0, 255]. If you try to assign it to 256, it will happenInteger overflow(integer overflow), causing one of two behaviors:

  • Debug mode compilation: Rust will perform an overflow check, and once it is found, it will be runpanic(The program crashes and exits).
  • Release mode compilation: Rust does not perform overflow checks, but performsTwo's complement surround(two’s complement wrapping). In other words, when the maximum representable value is exceeded, it will "surround" back to the minimum value. For example,u8Type, 256 will become 0, 257 will become 1, etc. Panic will not appear, but the results are often inconsistent with expectations.

In actual development, the surrounding behavior of integer overflow should not be relied upon, which is considered a wrong approach. If overflows need to be handled explicitly, you can use the following method families provided by the standard library for integers:

  • wrapping_*:likewrapping_add, always perform surround operations;
  • checked_*:likechecked_add, if overflowing, returnNone
  • overflowing_*:likeoverflowing_add, return a tuple(Result, bool),inboolIndicates whether an overflow occurred;
  • saturating_*:likesaturating_add, the result will automatically "saturate" to the minimum or maximum value of the corresponding type when overflowing.

2. Floating-Point Types

Rust provides two native floating point types:f32(32 bits) andf64(64 bits). Used by defaultf64, because on modern CPUs,f64andf32The speed is almost the same, but the accuracy is higher. All floating point types are signed numbers.

fn main() {
    let x = 2.0;    // f64
    let y: f32 = 3.0;  // f32
    println!("x = {}, y = {}", x, y);
}

Rust's floating point numbers follow the IEEE-754 standard.

3. Numeric Operations

Rust supports common numerical operations: addition, subtraction, multiplication, division and balance. It should be noted thatInteger divisionWill round in the zero direction (truncate the decimal part). Example:

fn main() {
    // Addition    let sum = 5 + 10;
    // Subtraction    let difference = 95.5 - 4.3;
    // Multiplication    let product = 4 * 30;
    // Division    let quotient = 56.7 / 32.2;
    // Take the rest    let remainder = 43 % 5;
    println!("sum = {}", sum);
    println!("difference = {}", difference);
    println!("product = {}", product);
    println!("quotient = {}", quotient);
    println!("remainder = {}", remainder);
}

If you need to view all operators provided by Rust, you can refer toAppendix B

4. Boolean Type

Boolean type (bool) There are only two possible values:trueandfalse. It takes up 1 byte in size. For example:

fn main() {
    let t = true;
    let f: bool = false;
    println!("t = {}, f = {}", t, f);
}

Booleans are often used for conditional judgments (e.g.ifExpression), which will be described in detail later in the "Control Flow" section.

5. Character Type

Rust'scharTypes are the most basic letter types, wrapped in single quotes, and support Unicode Scalar Value. This means it can represent more characters than ASCII, such as accented Latin characters, Chinese, Japanese, Korean, emoji, zero-width spaces, etc. For example:

fn main() {
    let c = 'z';
    let z = 'ℤ';
    let heart_eyed_cat = '😻';
    println!("{}, {}, {}", c, z, heart_eyed_cat);
}

Rust'scharThe type occupies 4 bytes, corresponding to the Unicode Scalar Value range:U+0000 ~ U+D7FFandU+E000 ~ U+10FFFF. It should be noted that Unicode's concept of "character" may not be exactly consistent with the "character" in people's intuition. For details, please refer to the following sectionChapter 8 Discussion on Strings

2. Compound Types

A composite type can combine multiple values ​​into one type. Rust provides two native composite types:Tuples(tuple) andArray(array)。

1. Tuple Type

Tuples can combine multiple values ​​of different types into a compound type with fixed lengths and cannot be increased or shortened. Use brackets()Contain and separate different values ​​with commas. For example:

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    println!("tup = {:?}", tup);
}

1.1 Destructuring tuples

To get individual values ​​in tuples, you can deconstruct using pattern matching:

fn main() {
    let tup = (500, 6.4, 1);
    let (x, y, z) = tup;
    println!("y = {}", y);
}

After execution,yThe value is6.4. heretupBeing "disassembled" intox, y, zThe process of three variables is calledDeconstruction

1.2 Accessing tuples using indexes

You can also directly use dot numbers and indexes to access the specified elements of a tuple:

fn main() {
    let x: (i32, f64, u8) = (500, 6.4, 1);
    let five_hundred = x.0;
    let six_point_four = x.1;
    let one = x.2;
    println!("{}, {}, {}", five_hundred, six_point_four, one);
}

It should be noted that the index starts at 0.

1.3 Unit Type

If the tuple does not contain any elements, it is calledUnit Tuples(unit). It's written(), represents a null value or a null return type. If an expression does not return any other value, the unit tuple is returned by default.

2. Array Type

Arrays are also a way to combine multiple values, but they have two main differences from tuples:

  • In the arrayAll elements have the same type
  • ArrayFixed length, Once declared, the length cannot be changed.

For example:

fn main() {
    let a = [1, 2, 3, 4, 5];
    println!("{:?}", a);
}

Arrays are usually stored inStackon (stack) instead of heap, this isChapter 4Will explain in detail. If a scalable sequence is required, use thevector(vector,Vec<T>). If you need a fixed-length sequence, arrays are perfect. For example, the month name:

let months = [
    "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
];

2.1 Type annotation for arrays

When declaring an array type, you need to write element type, semicolon, and number of elements in square brackets:

let a: [i32; 5] = [1, 2, 3, 4, 5];

herei32is the type of each element,5Represents the length of the array.

2.2 Initialize to the same element

If you want all elements of the array to be the same, you can use the following syntax:

let a = [3; 5];
// Equivalent to let a = [3, 3, 3, 3, 3];

2.3 Accessing array elements

You can use indexes to access array elements:

fn main() {
    let a = [1, 2, 3, 4, 5];
    let first = a[0];
    let second = a[1];
    println!("first = {}, second = {}", first, second);
}

2.4 Out-of-bounds access and runtime errors

If the index exceeds the length of the array, Rust will beRuntimeCheck for an error and panic:

fn main() {
    let a = [1, 2, 3, 4, 5];
    println!("Please enter an array index.");
    let mut index = String::new();
    std::io::stdin()
        .read_line(&amp;mut index)
        .expect("Read failed");
    let index: usize = index
        .trim()
        .parse()
        .expect("The index of the input is not a number");
    let element = a[index];
    println!("The element you choose is:{}", element);
}

If you typed out[0..4]The index of the range, such as 10, will trigger a panic, showing something like:

thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/:19:19

The program exits and will not execute subsequentprintln!. This is the embodiment of Rust's memory security: many low-level languages ​​may access illegal memory addresses when indexed out of bounds, causing unpredictable consequences, while Rust detects and exits directly at runtime to ensure security.

summary

In this article, we introduce two of the most commonly used subsets of data types in Rust:Scalar TypeandCompound type. Scalar types include integers, floating point numbers, booleans, and characters, each with different representations and ranges; composite types include tuples and arrays, which can be used to combine multiple values ​​into one type, and differ in terms of whether the length is mutable and type consistency.

  • Scalar Type
    • Integer:likei32, u32, i8, u8etc. Different word lengths and signed/unsigned selection;
    • Floating point numberf32andf64, defaultf64
    • Boolebool, onlytrueandfalse
    • characterchar, accounting for 4 bytes, can represent Unicode Scalar Value.
  • Compound type
    • Tuples: Can contain multiple types, fixed length; can be accessed using deconstruction or indexing;
    • Array: A collection of elements of the same type, with a fixed length and stored on the stack.

For novices, when encountering situations where types cannot be automatically inferred, type annotations are required, especially when usingparseOr other scenarios where specific numerical types need to be specified. As practice deepens, the various security check mechanisms provided by Rust (such as integer overflow checking, array out-of-bounds checking, etc.) will give you more confidence and a sense of security, and you also need to be familiar with these mechanisms to write efficient and secure code.

In subsequent chapters, we will continue to deepen the characteristics of Rust, including ownership, references and slices, collection types (vectors, strings, hash mappings), and error handling. We hope that you can continue to explore and learn Rust.

References and thanks

  • The Rust Programming Language - By Steve Klabnik and Carol Nichols, CC BY 4.0
  • Part of this article is based on its translation and rewriting. If you need more details, please read the official documentation.

This is the end of this article about the detailed explanation of Rust data types. For more related Rust data types, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!