Some common concepts in Rust language (Part 1)

Table of contents

1. Variability of variables

constant

 Hide

2. Data type

2.1 Scalar types

integer

floating point

Numerical operations

boolean

Character type

composite type

tuple type

array type


1. Variability of variables

Variables are immutable by default. This is one of the many advantages that Rust gives you, allowing you to write code that takes full advantage of the safety and simple concurrency that Rust provides. However, you can still use mutable variables.

Next, let’s test it. Use the cargo new variables command to generate a new project called variables in the projects directory.

Modify main.rs as follows:

fn main() {
    let v = 1;
    v = 2;
    println!("Hello, world! {v}");
}

Opening it in VSCode, we found that the rust-analyzer plug-in prompted that immutable variables could not be modified.

But variability is also very useful and can be used to write code more easily. Although variables are immutable by default, you can still make them mutable by adding mut in front of the variable name. The code changes to the following:

fn main() {
    let mut v = 1;
    println!("Hello, world! {v}");
    v = 2;
    println!("Hello, world! {v}");
}

constant

Similar to immutable variables,constants are values ​​bound to a name that are not allowed to change, but constants and variables There are still some differences.

First, the use of mut with constants is not allowed. Constants are not only immutable by default, they are always immutable. To declare a constant, use the const keyword instead of let, and must declare the type of the value .

Change the above code to look like this:

fn main() {
    const PI: f64 = 3.14159;
    println!("Hello, world! {PI}");
}

 Hide

In the same scope, you can declare a variable multiple times, use the same variable name to hide a variable, and reuse the let keyword to hide it multiple times, as shown below:

fn main() {
    let name = "zhangsan";
    let name = "lisi";
    println!("我的名字是:{name}");
    {
        let name = "wangwu";
        let name = "zhaoliu";
        println!("我的名字是:{name}");
    }
}

The corresponding result will be printed, but there will be a prompt where the definition is repeated, saying that the variable is not referenced. If it is intentional, it is recommended to add an underscore prefix.

There is a difference between hiding and marking a variable as mut . When you accidentally try to reassign a variable without using the let keyword, it will cause a compile-time error. By using let, we can do some calculations with this value, but the variable will still be immutable after the calculation.

mut Another difference between and hiding is that when let is used again, a new variable is actually created. We can change the type of the value and reuse the name. For example, suppose the program asks the user to enter a space character to indicate how many spaces they want to appear between text, and next we want to store the input as a number (how many spaces):

fn main() {
    let spaces = "zhangsan";
    let spaces = spaces.len();
    println!("长度是:{spaces}")
}

In editing, you can see that the same variable is assigned a value and the corresponding type has also changed.

The first spaces variable is of string type, and the second spaces variable is of numeric type. Hiding saves us from having to use different names. What happens if we declare a mutable variable via mut?

fn main() {
    let mut spaces = "zhangsan";
    spaces = spaces.len();
    println!("长度是:{spaces}");
}

This shows that at the beginning, the type of the variable we declared was fixed, and we cannot change the type of the variable.

2. Data type

Each value belongs to a certain data type (data type), this tells Rust what kind of data it is designated as, so that it is clear how the data is handled. We will see two subsets of data types: scalar and compound

When uses parse to convert String into a number, a type annotation must be added, like this:

let guess:u32 = "100".parse().expect("");

If no type definition is added to guess, the following error will occur:

2.1 Scalar types

The scalar (scalar) type represents a single value. Rust has four basic scalar types: integers, floats, booleans, and characters.

integer

Integer is a number without a decimal part. The u32 integer type was used in the previous example. This type declaration indicates that the value associated with it should be an unsigned integer occupying 32 bits (signed integer types begin with i instead of u), as follows The table shows Rust's built-in integer types.

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

isize The and usize types depend on the computer architecture on which the program is running: they are 64-bit on a 64-bit architecture, and 32-bit on a 32-bit architecture.

Note: Numeric literals that can be of multiple numeric types allow the use of type suffixes, such as 57u8 to specify the type, and also allow the use of < /span>  you specified. , its value is the same as the _ is used as a delimiter to facilitate reading, for example, 1_0001000

numeric literal example
Decimal (decimal) 98_222
Hex (hexadecimal) 0xff
Octal (octal) 0o77
Binary 0b1111_0000
Byte (single-byte character) (u8 only) b'A'

floating point

Rust also has two native floating-point numbers (floating-point numbersf32< a i=4>) type, they are numbers with a decimal point. Rust's floating point types are  and f64, which occupy 32 and 64 bits respectively. The default type is f64 because on modern CPUs it is almost as fast as f32 but with more precision. All floating point types are signed.

Here is an example showing floating point numbers:

Floating point numbers are represented by the IEEE-754 standard. f32 is a single-precision floating-point number, and f64 is a double-precision floating-point number.

Numerical operations

All numeric types in Rust support basic mathematical operations: addition, subtraction, multiplication, division, and remainder. Integer division rounds toward zero to the nearest integer. Here are some examples:

fn main() {
    let plus = 2 + 3;
    let sub = 5 - 2;
    let mul = 2 * 3;
    let div = 3 /2;
    let rem = 3 % 2;
    println!("{plus} - {sub} - {mul} - {div} - {rem}") 
}

boolean

The Boolean type in Rust has two possible values: true and false. Boolean types in Rust are represented using bool . For example:

fn main() {
    let a = false;
    let b:bool = true;
    print!("{a} {b}")
}

Character type

Rust’s char type is the most native alphabetic type in the language. Here are some examples of declaring char values:

fn main() {
    let a = 'A';
    let b:char = 'a';
    println!("{a} - {b}")
}

composite type

Composite types can combine multiple values ​​into a single type. Rust has two native composite types: tuples and arrays.

tuple type

Tuples are a primary way to combine values ​​from multiple other types into a composite type. A tuple has a fixed length: once declared, its length does not grow or shrink.

We create a tuple using a comma-separated list of values ​​enclosed in parentheses. Each position in the tuple has a type, and the types of the different values ​​do not have to be the same. This example uses optional type annotations:

let tup: (char, f32, bool) = ('A', 3.2, true); 

tup The variable is bound to the entire tuple because the tuple is a single composite element. To get a single value from a tuple, you can use pattern matching to destructure the tuple value, like this:

fn main() {
    let tup: (char, f32, bool) = ('A', 3.2, true); 
    let (x,y,z) = tup;
    println!("{x} {y} {z}") // A 3.2 true
}
array type

Another way to contain multiple values ​​is array (array). Unlike tuples, each element in an array must be of the same type. Arrays in Rust differ from arrays in some other languages ​​in that arrays in Rust have a fixed length.

fn main() {
    let x = [1, 2, 3, 4, 5];
}

You can also create an array with the same value for each element by specifying the initial value in square brackets followed by a semicolon and then the number of elements:

fn main() {
    let a = [3; 5];
}

The array named a will contain 5 elements, and the values ​​of these elements will initially be set to 3. This way of writing has the same effect as let a = [3,3,3,3,3].

Access array elements

fn main() {
    let x = [1, 2, 3, 4, 5];
    let y = x[0];
    let z = x[9];
    println!("{z}")
}

We can get the value through the index of the array, just like getting the value in js and ts languages.

When accessing an index that exceeds the bounds, a runtime error will be reported.

The program caused a runtime error when it used an invalid value in an indexing operation. The program exits with an error message and does not execute the final println! statement. When trying to access an element using an index, Rust checks whether the specified index is less than the length of the array. If the index exceeds the length of the array, Rust panics , which is Rust terminology for when a program exits with an error. This check must be done at runtime, especially in this case, because the compiler has no way of knowing what values ​​the user will enter when the code is later run.

Guess you like

Origin blog.csdn.net/u014388408/article/details/134072912