diff --git a/Languages/en/01_HelloRust/hello_cargo/Cargo.toml b/Languages/en/01_HelloRust/hello_cargo/Cargo.toml new file mode 100644 index 0000000..4ab7042 --- /dev/null +++ b/Languages/en/01_HelloRust/hello_cargo/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "hello_cargo" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[profile.dev] +debug = true # Include debug info +opt-level = 0 # No optimization diff --git a/Languages/en/01_HelloRust/hello_cargo/src/main.rs b/Languages/en/01_HelloRust/hello_cargo/src/main.rs new file mode 100644 index 0000000..430e888 --- /dev/null +++ b/Languages/en/01_HelloRust/hello_cargo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, rust!"); +} diff --git a/Languages/en/01_HelloRust/imgs/img.png b/Languages/en/01_HelloRust/imgs/img.png new file mode 100644 index 0000000..36a6323 Binary files /dev/null and b/Languages/en/01_HelloRust/imgs/img.png differ diff --git a/Languages/en/01_HelloRust/readme.md b/Languages/en/01_HelloRust/readme.md new file mode 100644 index 0000000..c951595 --- /dev/null +++ b/Languages/en/01_HelloRust/readme.md @@ -0,0 +1,112 @@ +--- +title: 1. Hello Rust +tags: + - Rust + - Install + - Cargo + - wtfacademy +--- + +# WTF Rust Minimalist Introduction: 1. Hello Rust + +I am recently relearning `Rust` to solidify the details and to write a `WTF Rust Minimalist Introduction` for beginners (advanced programmers can find other tutorials). I will update it 1-3 times per week. + +## Introduction to Rust + +`Rust` is a systems programming language developed by Mozilla Research, focusing on safety, speed, and concurrency. It aims to help developers build reliable, efficient software systems while preventing common security vulnerabilities, such as null pointer dereferences and buffer overflows. + +The design principles of `Rust` include zero-cost abstractions, guaranteed memory safety, data-race-free concurrency, and pragmatism. Through mechanisms like ownership, borrowing, and lifetimes, it ensures memory safety while avoiding the performance overhead of garbage collection. + +## Installing Rust + +First, we need to install `Rust` on your machine. `Rust` has a fantastic installation tool called `rustup`, which helps us manage `Rust` versions and the corresponding toolchains. Let's install it! + +On `macOS`, `Linux`, or Unix-like operating systems, install using the following command: + +Open your terminal (or command line) and enter the following command: + +```Bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +This command will download a script and execute it. The script will automatically install `rustup` and the default version of Rust (including `rustc`, the Rust compiler, and `cargo`, the Rust package manager). Follow the instructions in the terminal, and once everything is set up, we can proceed to the next step! + +After installation is complete, you can check the Rust version by running the `rustc --version` command to verify if the installation was successful. If it indicates that `rustc` cannot be found, it is an environment variable issue. Check whether the directory `~/.cargo/bin` has been added to `PATH`. You can restart the terminal or manually source it to apply the environment changes. + +If it is the `Windows` system, please refer to [Official Installation Instructions](https://forge.rust-lang.org/infra/other-installation-methods.html) + +## Hello Rust program + +In the journey of programming language, the program is the first step of the traditional. It is the simplest program that "ask well" to the world. It is no exception in Rust, let's try it! + +1. Create a new folder, named `Hello_rust`, and then enter this folder. +2. In the `Hello_rust` folder, create a new file, named` main.rs`. The file name `.s` suffix represents a RUST source file. +3. Open the `main.rs`, use your favorite text editor, enter the following code: + +```rust +fn main () { + Println! ("Hello, Rust!"); +} +``` + +To explain briefly, this code defines a function `main`, which is the entrance point of each Rust program. When the Rust program runs, it executes the code in the `main` function. `Println!` is a macro (we talk about macro in the future), used to output text to the terminal. + +4. Save the file and return to the terminal to make sure you are in the `Hello_rust` folder, and then enter the following command to compile and run your program: + +```Bash +Rustc Main.rs +./main +``` + +If you are a user, the command of the running program may be slightly different, such as entering the `main` directly. + +If everything goes well, your terminal will output: + +``` +Hello, Rust! +``` + +Congratulations, you have successfully run your first Rust program! + +## Use Cargo + +In Rust's world, `Cargo` is your good friend. It is not only a bag management tool, but also helps you build projects, download dependencies, run tests, and so on. Let's take a look at how to use the `Cargo` to create and run a new project. + +1. Open the terminal and enter the following command to create a new RUST project: + +```Bash +Cargo new hello_cargo +``` + +This command will create a new folder called `Hello_cargo`, which contains a preliminary project structure. + +2. Enter the `Hello_cargo` folder, you will find that there are two main files:` cargo.toml` and `src/main.rs`. `Cargo.toml` is your project configuration file, while` src/main.rs` is your main program file, which has the default `Hello, Rust!` Code. + +3. Let's compile and run the project directly to see the magic of `Cargo`! In the terminal of the `hello_cargo` folder, enter the following command: + +```Bash +Cargo run +``` + +`Cargo Run` command will automatically compile your code (if necessary) and run the generated program. You should see the greetings of `Hello, Rust!` In the terminal. + + +4. If you use Rustrover, you can directly run the program directly in the `Cargo` plug -in that comes with your own` Cargo` plug -in to facilitate the rapid verification of the program. + +![img.png](imgs/img.png) + +5. In the demonstration code in the subsequent chapters, I will use `Cargo` to demonstrate, so that everyone will run and test. + +that's all! Now, you already know how to install the `Rust`, write and run the` Rust` program, and use the simple item to manage the `Cargo`. This is just the tip of the iceberg. The world of `Rust` is full of possibilities and adventures waiting for you. Are you ready? Let's move forward and go deep into the wonderful journey of `Rust`! + +## Summary + +This chapter mainly introduces the `Rust` installation method, write the first` Rust` program --`hello Rust`, and introduce how to use `Cargo` for project development + + + + + + + + diff --git a/Languages/en/02_BaseType/Cargo.toml b/Languages/en/02_BaseType/Cargo.toml new file mode 100644 index 0000000..afd14bc --- /dev/null +++ b/Languages/en/02_BaseType/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "base_type" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/Languages/en/02_BaseType/README.md b/Languages/en/02_BaseType/README.md new file mode 100644 index 0000000..4d3e146 --- /dev/null +++ b/Languages/en/02_BaseType/README.md @@ -0,0 +1,145 @@ +--- +title: 2. Base Type +tags: +- Rust +- Variables +- wtfacademy +--- + +# WTF Rust Minimalist Introduction: Base Types + +In this chapter, we will explore the basic syntax elements in Rust through examples with detailed explanations. We will cover variables and mutability, as well as data types (including scalar and compound types). + +## Variables and Mutability + +In Rust, variables are immutable by default. This means that once a value is assigned to a variable, you cannot change it. However, you can use the `mut` keyword to make a variable mutable. + +### Immutable Variables + +```rust +let x = 5; +println!("The value of x is: {}", x); +// x = 6; // This line will cause a compile error because x is immutable +``` + +### Mutable Variables + +```rust +let mut y = 5; +println!("The value of y is: {}", y); +y = 6; // This is allowed because y is mutable +println!("The value of y is: {}", y); +``` + +## Data Types + +Rust is a statically typed language, meaning all variable types must be known at compile time. The compiler usually infers types based on values and usage. Rust data types can be broadly divided into two categories: scalar and compound types. + +### Scalar Types + +Scalar types represent single values. As previously mentioned, Rust has four primary scalar types: integers, floating-point numbers, booleans, and characters. + +#### Integers + +Integers are numbers without fractional parts. In Rust, integer types are divided into signed and unsigned. For example, the `i32` type represents a signed 32-bit integer (`i` stands for `integer`). The `u` prefix indicates an unsigned type. Here are the built-in integer types available in Rust: + +| Length | Signed Type | Unsigned Type | +|:------------:|:-----------:|:-------------:| +| 8-bit | `i8` | `u8` | +| 16-bit | `i16` | `u16` | +| 32-bit | `i32` | `u32` | +| 64-bit | `i64` | `u64` | +| 128-bit | `i128` | `u128` | +| Architecture | `isize` | `usize` | + +For signed types, the numeric range is from `-(2^(n-1))` to `2^(n-1) - 1`, where `n` is the number of bits. For example, `i8` can store values from `-128` to `127`. Unsigned types range from `0` to `2^n - 1`, so `u8` ranges from `0` to `255`. + +The size of `isize` and `usize` depends on the architecture of the computer running the program: 32 bits for 32-bit CPUs and 64 bits for 64-bit CPUs. + +Integer literals can be represented in several ways: + +- Decimal: without a prefix, e.g., 98_222 (underscores improve readability) +- Hexadecimal: with a `0x` prefix, e.g., 0xff +- Octal: with a `0o` prefix, e.g., 0o77 +- Binary: with a `0b` prefix, e.g., 0b1111_0000 +- Byte (only for `u8` type): with a `b` prefix, e.g., b'A' + +```rust +let x: i32 = -123; +let y: u32 = 123; +println!("x is {}, y is {}", x, y); +``` + +#### Floating-Point Numbers + +Rust provides two floating-point types: single precision `f32` and double precision `f64`. By default, floating-point numbers are of type `f64` because it offers good precision and speed. + +| Type | Precision | +|:----:|:--------------------:| +| `f32`| Single precision (32-bit) | +| `f64`| Double precision (64-bit) | + +```rust +let x = 2.0; // No type specified, inferred as f64 (default) +let y: f32 = 3.0; // Explicitly specified as f32 +println!("x is {}, y is {}", x, y); + +let x1 = 2.0; // No type specified, but will be inferred as f32 because of the next statement +let y1: f32 = 3.0; // Explicitly specified as f32 +let z1 = x1 + y1; +println!("x1 is {}, y1 is {} z1 is {}", x1, y1, z1); +``` + +#### Booleans + +```rust +let t = true; +let f: bool = false; // Explicit type annotation +println!("t is {}, f is {}", t, f); +``` + +#### Characters + +Characters, encoded in Unicode, are 4 bytes in size in Rust: + +```rust +let c = 'z'; +let z = 'ℤ'; +let heart_eyed_cat = '😻'; +println!("c is {}, z is {}, heart_eyed_cat is {}", c, z, heart_eyed_cat); +println!("The character 'c' occupies {} bytes in memory", std::mem::size_of_val(&c)); +``` + +In Rust, the length of the `String` type depends on the encoding used. By default, Rust uses UTF-8 encoding, where each character occupies 1-4 bytes. The `char` type always occupies 4 bytes, even if some characters need only 1-3 bytes in specific encodings. The advantages are: +- Ensuring all `char` values occupy a fixed size in memory, aiding memory alignment and access efficiency. +- Avoiding the overhead of encoding conversion, directly using 4-byte values for efficient processing. +- Adequately representing all Unicode scalar values, ensuring future compatibility. + +### Compound Types + +Compound types can group multiple values into one type. Rust includes tuples and arrays as compound types. + +#### Tuples + +Tuples are a basic way to group multiple values of different types into one compound type with a fixed length. + +```rust +let tup: (i32, f64, u8, char) = (-500, 6.4, 1, 'z'); +let (w, x, y, z) = tup; // Destructuring the tuple +println!("The value of x is: {}", x); +``` + +#### Arrays + +Arrays group multiple values of the same type. Unlike tuples, arrays have a fixed length. + +```rust +let a = [1, 2, 3, 4, 5]; +let first = a[0]; +let second = a[1]; +println!("The first element is {}, the second element is {}", first, second); +``` + +## Summary + +In this chapter, we covered Rust's basic data types: the four basic scalar types (integers, floating-point numbers, booleans, and characters) and the two compound types (tuples and arrays). diff --git a/Languages/en/02_BaseType/src/main.rs b/Languages/en/02_BaseType/src/main.rs new file mode 100644 index 0000000..3db2e58 --- /dev/null +++ b/Languages/en/02_BaseType/src/main.rs @@ -0,0 +1,36 @@ +fn main() { +let x_immutable = 5; +println!("The value of x_immutable is: {}", x_immutable); +// x_immutable = 6; // This line will cause a compilation error because x_immutable is immutable + +let mut y_mutable = 5; +println!("The value of y_mutable is: {}", y_mutable); +y_mutable = 6; // This is allowed because y_mutable is mutable +println!("The value of y_mutable is: {}", y_mutable); + +let x_int_neg: i32 = -123; +let y_uint_pos: u32 = 123; +println!("x_int_neg is {}, y_uint_pos is {}", x_int_neg, y_uint_pos); + +let x_float64 = 2.0; // defaults to f64 +let y_float32: f32 = 3.0; // explicitly declared as f32 +println!("x_float64 is {}, y_float32 is {}", x_float64, y_float32); + +let t_bool = true; +let f_bool: bool = false; // explicit type declaration +println!("t_bool is {}, f_bool is {}", t_bool, f_bool); + +let c_char = 'z'; +let z_char = 'ℤ'; +let heart_eyed_cat_char = '😻'; +let z_string = String::from("string"); +println!("c_char is {}, z_char is {}, heart_eyed_cat_char is {}", c_char, z_char, heart_eyed_cat_char); +println!("The character 'c_char' occupies {} bytes of memory size", std::mem::size_of_val(&c_char)); +println!("The string 'z_string' content occupies {} bytes of memory size", &z_string.as_bytes().len()); + +let tup_var: (i32, f64, u8, char) = (-500, 6.4, 1, 'z'); +let (_w_from_tup, x_from_tup, _y_from_tup, _z_from_tup) = tup_var; // Deconstruct tuple +println!("The value of x_from_tup is: {}", x_from_tup); + +let a_array = [1, 2, 3, 4, 5]; +let first_element = a_array[0]; let second_element = a_array[1]; println!("The first element is {}, the second element is {}", first_element, second_element); } diff --git a/Languages/en/03_CompoundType/Cargo.toml b/Languages/en/03_CompoundType/Cargo.toml new file mode 100644 index 0000000..32be50a --- /dev/null +++ b/Languages/en/03_CompoundType/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "compound_type" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.10" diff --git a/Languages/en/03_CompoundType/README.md b/Languages/en/03_CompoundType/README.md new file mode 100644 index 0000000..5098f88 --- /dev/null +++ b/Languages/en/03_CompoundType/README.md @@ -0,0 +1,87 @@ +--- +title: 3. Compound Type +tags: +- Rust +- basic +- wtfacademy +--- + +# WTF Rust Minimalist Introduction: Compound Types Expanded: Tuples, Arrays, Strings, and Slices + +## Tuples + +A tuple is a compound type that can contain multiple values of different types with a fixed length. Once defined, the length of a tuple cannot grow or shrink, and indices start from 0. Tuples are very useful when you want to return multiple values from a function or group multiple values into a single collection. + +### Example Code + +```rust +fn main() { + let mixed = ("Rust", 2023, 3.14, true); + let (lang, year, pi, status) = mixed; + + println!("Language: {}, Year: {}, PI: {}, Status: {}", lang, year, pi, status); +} +``` + +## Dynamic Arrays (Vectors) + +Dynamic arrays, `Vec`, are flexible data structures that allow for resizing at runtime. This means their length can be changed dynamically to add or remove elements as needed. They are particularly useful for handling an uncertain number of data elements, such as reading an unknown number of user inputs or dynamically generating datasets. Dynamic arrays use a generic parameter `T`, meaning they can store values of **any type**, such as integers, characters, or floating-point numbers discussed earlier, but once the type is specified, all elements in the array must be of the **same type**. + +### Example Code + +```rust +fn main() { + // 1. Explicitly declare the type of the dynamic array + let mut v1: Vec = Vec::new(); + v1.push(1); + v1.push(2); + v1.push(3); + println!("vector v1: {:?}", &v1); + + // 2. Use the macro vec! to create an array with initial values + let v2 = vec![1u8, 2, 3]; + println!("vector v2: {:?}", &v2); +} +``` + +## Strings and Slices + +Strings are a very common compound type used to store text. In `Rust`, there are two main string types: `String` and string slices `&str`. + +### Creating and Using Strings + +```rust +fn main() { + let mut s = String::from("Hello"); // Mutable String type + s.push_str(", world!"); // Modify the String + println!("{}", s); + + let slice = &s[0..5]; // Get a slice of the String + println!("Slice: {}", slice); +} +``` + +A string slice `&str` is a reference to a `UTF-8` encoded string data stored somewhere (usually a `String` type) and is hardcoded into the program binary at compile time, making it immutable. Slices are particularly useful when you want to reference a portion of a `String` or pass a small amount of data. + +## Slices + +Slices allow you to reference a contiguous sequence of elements within a collection rather than the entire collection. They are also applicable to arrays. + +### Example Code + +```rust +fn main() { + let numbers = [1, 2, 3, 4, 5]; + let slice = &numbers[1..4]; // Reference a part of the array + + for &item in slice.iter() { + println!("{}", item); + } +} +``` + +Here, `slice` is a reference to a portion of the `numbers` array containing three elements. Slices are a very useful tool because they allow you to safely access a subset of elements from an array or string without copying them. + +## Summary + +By exploring tuples, arrays, strings, and slices, we gain a more comprehensive understanding of compound types in `Rust` and their advantages. These structures offer flexibility and efficiency in handling data and organizing program logic. Hopefully, these examples help you better understand these concepts and effectively use them in your `Rust` projects. diff --git a/Languages/en/03_CompoundType/src/main.rs b/Languages/en/03_CompoundType/src/main.rs new file mode 100644 index 0000000..37b6e13 --- /dev/null +++ b/Languages/en/03_CompoundType/src/main.rs @@ -0,0 +1,38 @@ +use itertools::Itertools; + +fn main() { + let mixed = ("Rust", 2023, 3.14, true); + let (lang, year, pi, status) = mixed; + + println!("Language: {}, Year: {}, PI: {}, Status: {}", lang, year, pi, status); + + + // 1. Explicitly declare the type of the dynamic array + let mut v1: Vec = Vec::new(); + v1.push(1); + v1.push(2); + v1.push(3); + println!("vector v1: {:?}", &v1); + + // 2. Use the macro vec! to create an array with initial values + let v2 = vec![1u8, 2, 3]; + println!("vector v2: {:?}", &v2); + + let mut s = String::from("Hello"); // Mutable String type + s.push_str(", world!"); // Modify the String + println!("{}", s); + + let slice = &s[0..5]; // Get a slice of the String; the first parameter is the start index (inclusive), the second parameter is the end index (exclusive) + println!("Slice: {}", slice); // Hello + + + let numbers = [1, 2, 3, 4, 5]; + // Add numbers 6 and 7 to the array numbers + + let slice = &numbers[0..2]; // Reference a part of the array + + for &item in slice.iter() { + println!("{}", item); + } + slice.iter().for_each(|&item| println!("{}", item)); +} diff --git a/Languages/en/04_Struct_Enum/Cargo.toml b/Languages/en/04_Struct_Enum/Cargo.toml new file mode 100644 index 0000000..b45f3b0 --- /dev/null +++ b/Languages/en/04_Struct_Enum/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "struct_enum" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/Languages/en/04_Struct_Enum/README.md b/Languages/en/04_Struct_Enum/README.md new file mode 100644 index 0000000..e7608cc --- /dev/null +++ b/Languages/en/04_Struct_Enum/README.md @@ -0,0 +1,83 @@ +--- +title: 4. Structs and Enums +tags: +- Rust +- basic +- wtfacademy +--- + +# WTF Rust Minimalist Introduction: 4. Structs and Enums + +## 1. Defining and Using Structs + +First, let's talk about structs. A struct is like a custom data type used to represent entities in the real world, such as people, animals, or anything else we want to create. For example, to describe a person with attributes like age, name, and address, we can define a struct. It looks like this: + +```rust +// Define a Person struct +struct Person { + name: String, + age: u32, + address: String, +} + +fn main() { + // Create a Person instance with the name Alice and age 30 + let person1 = Person { + name: String::from("Alice"), + age: 30, + address: String::from("China"), + }; + + // Output the information of this Person instance + println!("{} is {} years old.", person1.name, person1.age); +} +``` + +## 2. Method Definitions + +Now, let's discuss methods, which are functions associated with structs. The difference between a `method` and a `function` is that a `method` has an **owner**, with its first parameter typically being `&self`, indicating the owner. When calling a method, you must specify the owner, like `owner.method()`. In contrast, a `function` has no owner and is considered a public function. The same program cannot have two functions with the same signature. Methods, having owners, allow different owners to have methods with the same signature. By using methods, we can provide behavior for structs. It sounds advanced but is actually simple: + +```rust +impl Person { + // Define a method to display personal information + fn show_info(&self) { + println!("{} is {} years old.", self.name, self.age); + } +} + +fn main() { + let person1 = Person { + name: String::from("Bob"), + age: 25, + }; + + // Call this method to display personal information + person1.show_info(); +} +``` + +## 3. Enums and Pattern Matching + +Next, let's talk about enums and pattern matching. Enums allow us to define various possible data variants, and then handle these variants through pattern matching. It sounds complex but is quite interesting: + +```rust +// Define an enum to represent different colors +enum Color { + Red, + Green, + Blue, +} + +fn main() { + let color = Color::Blue; + + // Use pattern matching to handle different colors + match color { + Color::Red => println!("The color is Red"), + Color::Green => println!("The color is Green"), + Color::Blue => println!("The color is Blue"), + } +} +``` + +By using structs and enums, we can better organize and manage data, and pattern matching allows us to handle data more flexibly. I hope this chapter helps you gain a clear understanding of structs and enums! diff --git a/Languages/en/04_Struct_Enum/src/main.rs b/Languages/en/04_Struct_Enum/src/main.rs new file mode 100644 index 0000000..85bbc8c --- /dev/null +++ b/Languages/en/04_Struct_Enum/src/main.rs @@ -0,0 +1,30 @@ +// Define a Person struct +struct Person { + name: String, + age: u32, +} + +impl Person { + // Define a method to display personal information + fn show_info(&self) { + println!("{} is {} years old.", self.name, self.age); + } +} + +fn show_info() { + println!("this is a function"); +} + +fn main() { + // Create a Person instance with the name Alice and age 30 + let person1 = Person { + name: String::from("Alice"), + age: 30, + }; + + // Call the method to display personal information + person1.show_info(); + + // Call this function without needing an owner + show_info(); +} diff --git a/Languages/en/05_Ownership/Cargo.toml b/Languages/en/05_Ownership/Cargo.toml new file mode 100644 index 0000000..ac44089 --- /dev/null +++ b/Languages/en/05_Ownership/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "Ownership" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/Languages/en/05_Ownership/README.md b/Languages/en/05_Ownership/README.md new file mode 100644 index 0000000..d89e419 --- /dev/null +++ b/Languages/en/05_Ownership/README.md @@ -0,0 +1,81 @@ +--- +title: 5. Ownership +tags: + - Rust + - basic + - wtfacademy +--- + +# WTF Rust Minimalist Introduction: Ownership, Borrowing, and References +This chapter covers the essence of `Rust`: ownership, borrowing, and references. These concepts are the foundation of `Rust`'s memory safety, helping developers write safe and efficient code while avoiding common errors found in traditional languages, such as null pointer access and data races. + +## 1. Ownership Rules + +In `Rust`, the core rules of the ownership system can be summarized as follows: + +- Every value has a single owner variable. +- A value can only have one owner at a time. +- When the owner goes out of scope, the value is dropped. + +These rules ensure memory safety and prevent leaks while avoiding manual memory management. + +### Example: Ownership Transfer + +```rust +fn main() { + let s1 = String::from("hello"); // s1 is the owner of the "hello" object + + let s2 = s1; // Ownership is transferred from s1 to s2; s1 becomes unusable + // println!("{s1}"); // Error: s1 no longer holds the string + + display(s2); // s2 transfers ownership to the function parameter s; s2 becomes unusable + // println!("{s2}"); // Error: s2 is no longer usable +} + +fn display(s: String) { + println!("{:?}", s); +} +``` + +## 2. Borrowing + +In `Rust`, borrowing refers to obtaining **access rights** to data via references, rather than **ownership**, denoted by the `&` symbol. Borrowing allows multiple parts of code to access the same data simultaneously without transferring ownership. Borrowing comes in two forms: immutable borrowing and mutable borrowing. + +- **Immutable Borrowing**: Allows multiple borrows, but the data cannot be modified during the borrowing period; `Rust` defaults to immutable borrowing. +- **Mutable Borrowing**: Allows data modification, but only one mutable borrow is allowed at a time. + +### Example: Immutable Borrowing + +```rust +fn main() { + let s1 = String::from("hello"); + let len = calculate_length(&s1); // s1 is immutably borrowed; the function can only read but not modify s1 + + println!("The length of '{}' is {}.", s1, len); +} + +fn calculate_length(s: &String) -> usize { // s is a reference to s1 + s.len() +} +``` + +### Example: Mutable Borrowing + +```rust +fn main() { + let mut s = String::from("hello"); + + change(&mut s); // s is mutably borrowed; the function can modify s + + println!("{}", s); +} + +fn change(some_string: &mut String) -> &mut String { + some_string.push_str(", wtf!"); + some_string +} +``` + +## Summary + +Through these examples, you should have a basic understanding of `Rust`'s core concepts: ownership and borrowing. Mastering these concepts is crucial for effectively utilizing `Rust`'s features, enabling you to write safer and more efficient code. If you have any questions or need further clarification, feel free to ask! diff --git a/Languages/en/05_Ownership/src/main.rs b/Languages/en/05_Ownership/src/main.rs new file mode 100644 index 0000000..a6673b2 --- /dev/null +++ b/Languages/en/05_Ownership/src/main.rs @@ -0,0 +1,34 @@ +fn display(s: String) { + println!("{:?}", s); +} + +fn calculate_length(s: &String) -> usize { + // s is a reference to s1 + s.len() +} + +fn change(some_string: &mut String) -> &mut String { + some_string.push_str(", wtf!"); + some_string +} + +fn main() { + let mut s1 = String::from("hello"); // s1 is the owner of the "hello" object + s1.push_str(", wtf!"); // s1 can modify the "hello" object by appending a string + + let s2 = s1; // Ownership is transferred from s1 to s2 + // println!("{s1}"); // Error: s1 no longer owns the string + + display(s2); // s2 transfers ownership to the function parameter s; s2 becomes unusable + // println!("{s2}"); // Error: s2 is no longer usable + + // Immutable Borrowing + let s3 = String::from("hello"); + let len = calculate_length(&s3); // s3 is immutably borrowed; the function can only read but not modify s3 + println!("The length of '{}' is {}.", s3, len); + + // Mutable Borrowing + let mut s4 = String::from("hello"); + change(&mut s4); // s4 is mutably borrowed; the function can modify s4 + println!("{}", s4); +}