This commit is contained in:
TimLai666 2024-06-18 18:29:13 +08:00 committed by GitHub
parent 6dc6b4c61a
commit 8f6d8ec21b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 59 additions and 83 deletions

View File

@ -1,12 +1,11 @@
# Smart Pointers
# 智慧型指標
In Rust, smart pointers are variables that contain an address in memory and reference some other data, but they also have additional metadata and capabilities.
Smart pointers in Rust often own the data they point to, while references only borrow data.
在 Rust 中智慧型指標是包含記憶體位址並引用其他資料的變數但它們還具有額外的元數據和功能。Rust 中的智慧型指標通常擁有它們指向的資料,而引用僅僅是借用資料。
## Further Information
## 進一步了解
- [Smart Pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html)
- [Rc\<T\>, the Reference Counted Smart Pointer](https://doc.rust-lang.org/book/ch15-04-rc.html)
- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
- [Cow Documentation](https://doc.rust-lang.org/std/borrow/enum.Cow.html)
- [智慧型指標](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
- [使用 Box 指向堆上的資料](https://doc.rust-lang.org/book/ch15-01-box.html)
- [Rc<T>,引用計數智慧型指標](https://doc.rust-lang.org/book/ch15-04-rc.html)
- [共享狀態並發](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
- [Cow 文檔](https://doc.rust-lang.org/std/borrow/enum.Cow.html)

View File

@ -1,29 +1,23 @@
// arc1.rs
//
// In this exercise, we are given a Vec of u32 called "numbers" with values
// ranging from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ] We would like to use this
// set of numbers within 8 different threads simultaneously. Each thread is
// going to get the sum of every eighth value, with an offset.
// 在此練習中,我們有一個 Vec<u32> 稱為 "numbers",其值範圍從 0 到 99 -- [0, 1, 2, ..., 98, 99]
// 我們希望在 8 個不同的線程中同時使用這組數字。每個線程將獲得每八個值的總和,並帶有一個偏移量。
//
// The first thread (offset 0), will sum 0, 8, 16, ...
// The second thread (offset 1), will sum 1, 9, 17, ...
// The third thread (offset 2), will sum 2, 10, 18, ...
// 第一個線程(偏移量為 0將總結 0, 8, 16, ...
// 第二個線程(偏移量為 1將總結 1, 9, 17, ...
// 第三個線程(偏移量為 2將總結 2, 10, 18, ...
// ...
// The eighth thread (offset 7), will sum 7, 15, 23, ...
// 第八個線程(偏移量為 7將總結 7, 15, 23, ...
//
// Because we are using threads, our values need to be thread-safe. Therefore,
// we are using Arc. We need to make a change in each of the two TODOs.
// 由於我們使用的是線程,我們的值需要是線程安全的。因此,我們使用 Arc。我們需要在兩個 TODO 處進行更改。
//
// Make this code compile by filling in a value for `shared_numbers` where the
// first TODO comment is, and create an initial binding for `child_numbers`
// where the second TODO comment is. Try not to create any copies of the
// `numbers` Vec!
// 通過在第一個 TODO 註釋處填入一個值,使這段代碼能夠編譯,並在第二個 TODO 註釋處創建一個 `child_numbers` 的初始綁定。儘量不要創建 `numbers` Vec 的任何副本!
//
// Execute `rustlings hint arc1` or use the `hint` watch subcommand for a hint.
// 執行 `rustlings hint arc1` 或使用 `hint` watch 子命令以獲取提示。
// I AM NOT DONE
#![forbid(unused_imports)] // Do not change this, (or the next) line.
#![forbid(unused_imports)] // 不要更改此行或下一行。
use std::sync::Arc;
use std::thread;

View File

@ -1,22 +1,15 @@
// box1.rs
//
// At compile time, Rust needs to know how much space a type takes up. This
// becomes problematic for recursive types, where a value can have as part of
// itself another value of the same type. To get around the issue, we can use a
// `Box` - a smart pointer used to store data on the heap, which also allows us
// to wrap a recursive type.
// 在編譯時Rust 需要知道一個類型佔用了多少空間。這對於遞迴類型來說會變得很麻煩,因為一個值可以包含同類型的另一個值。為了解決這個問題,我們可以使用 `Box` - 一個用來在堆上存儲數據的智能指針,它還允許我們包裝一個遞迴類型。
//
// The recursive type we're implementing in this exercise is the `cons list` - a
// data structure frequently found in functional programming languages. Each
// item in a cons list contains two elements: the value of the current item and
// the next item. The last item is a value called `Nil`.
// 我們在這個練習中實現的遞迴類型是 `cons 列表` - 一種在函數式程式語言中經常出現的資料結構。cons 列表中的每個項目包含兩個元素:當前項目的值和下一個項目。最後一項是一個名為 `Nil` 的值。
//
// Step 1: use a `Box` in the enum definition to make the code compile
// Step 2: create both empty and non-empty cons lists by replacing `todo!()`
// 第一步:在枚舉定義中使用 `Box` 來使代碼能夠編譯
// 第二步:通過替換 `todo!()` 創建空和非空的 cons 列表
//
// Note: the tests should not be changed
// 注意:不應該更改測試
//
// Execute `rustlings hint box1` or use the `hint` watch subcommand for a hint.
// 執行 `rustlings hint box1` 或使用 `hint` watch 子命令以獲取提示。
// I AM NOT DONE
@ -27,9 +20,9 @@ pub enum List {
}
fn main() {
println!("This is an empty cons list: {:?}", create_empty_list());
println!("這是一個空的 cons 列表: {:?}", create_empty_list());
println!(
"This is a non-empty cons list: {:?}",
"這是一個非空的 cons 列表: {:?}",
create_non_empty_list()
);
}

View File

@ -1,16 +1,12 @@
// cow1.rs
//
// This exercise explores the Cow, or Clone-On-Write type. Cow is a
// clone-on-write smart pointer. It can enclose and provide immutable access to
// borrowed data, and clone the data lazily when mutation or ownership is
// required. The type is designed to work with general borrowed data via the
// Borrow trait.
// 這個練習探索 Cow也就是 Clone-On-Write 類型。Cow 是一個延遲克隆的智慧指標。
// 它可以封裝並提供對借用數據的不可變訪問,並在需要變異或擁有時延遲克隆數據。
// 此類型設計為通過 Borrow 特徵來處理通用的借用數據。
//
// This exercise is meant to show you what to expect when passing data to Cow.
// Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the
// TODO markers.
// 這個練習旨在讓你了解將數據傳遞給 Cow 時會發生什麼。通過在 TODO 標記處檢查 Cow::Owned(_) 和 Cow::Borrowed(_) 來修復單元測試。
//
// Execute `rustlings hint cow1` or use the `hint` watch subcommand for a hint.
// 執行 `rustlings hint cow1` 或使用 `hint` 子命令以獲取提示。
// I AM NOT DONE
@ -20,7 +16,7 @@ fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {
for i in 0..input.len() {
let v = input[i];
if v < 0 {
// Clones into a vector if not already owned.
// 如果還未擁有,則克隆到向量中。
input.to_mut()[i] = -v;
}
}
@ -33,18 +29,18 @@ mod tests {
#[test]
fn reference_mutation() -> Result<(), &'static str> {
// Clone occurs because `input` needs to be mutated.
// 由於 `input` 需要變異,發生克隆。
let slice = [-1, 0, 1];
let mut input = Cow::from(&slice[..]);
match abs_all(&mut input) {
Cow::Owned(_) => Ok(()),
_ => Err("Expected owned value"),
_ => Err("預期為擁有值"),
}
}
#[test]
fn reference_no_mutation() -> Result<(), &'static str> {
// No clone occurs because `input` doesn't need to be mutated.
// 由於 `input` 不需要變異,未發生克隆。
let slice = [0, 1, 2];
let mut input = Cow::from(&slice[..]);
match abs_all(&mut input) {
@ -54,9 +50,8 @@ mod tests {
#[test]
fn owned_no_mutation() -> Result<(), &'static str> {
// We can also pass `slice` without `&` so Cow owns it directly. In this
// case no mutation occurs and thus also no clone, but the result is
// still owned because it was never borrowed or mutated.
// 我們也可以直接傳遞 `slice` 而不使用 `&`,這樣 Cow 直接擁有它。
// 在這種情況下不發生變異,因此也不會克隆,但結果仍然是擁有的,因為它從未被借用或變異。
let slice = vec![0, 1, 2];
let mut input = Cow::from(slice);
match abs_all(&mut input) {
@ -66,9 +61,8 @@ mod tests {
#[test]
fn owned_mutation() -> Result<(), &'static str> {
// Of course this is also the case if a mutation does occur. In this
// case the call to `to_mut()` in the abs_all() function returns a
// reference to the same data as before.
// 當然,如果發生變異,也是這種情況。
// 在這種情況下,對 abs_all() 函數中的 `to_mut()` 調用返回對與之前相同數據的引用。
let slice = vec![-1, 0, 1];
let mut input = Cow::from(slice);
match abs_all(&mut input) {

View File

@ -1,14 +1,10 @@
// rc1.rs
//
// In this exercise, we want to express the concept of multiple owners via the
// Rc<T> type. This is a model of our solar system - there is a Sun type and
// multiple Planets. The Planets take ownership of the sun, indicating that they
// revolve around the sun.
// 在這個練習中,我們想要通過 Rc<T> 類型來表達多個所有者的概念。這是一個我們的太陽系模型 - 有一個 Sun 類型和多個行星。行星擁有太陽,表示它們圍繞著太陽旋轉。
//
// Make this code compile by using the proper Rc primitives to express that the
// sun has multiple owners.
// 通過使用適當的 Rc 原語來使這個代碼編譯,表示太陽有多個所有者。
//
// Execute `rustlings hint rc1` or use the `hint` watch subcommand for a hint.
// 執行 `rustlings hint rc1` 或使用 `hint` 子命令以獲取提示。
// I AM NOT DONE
@ -38,68 +34,68 @@ impl Planet {
#[test]
fn main() {
let sun = Rc::new(Sun {});
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
println!("引用計數 = {}", Rc::strong_count(&sun)); // 1 個引用
let mercury = Planet::Mercury(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 2 個引用
mercury.details();
let venus = Planet::Venus(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 3 個引用
venus.details();
let earth = Planet::Earth(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 4 個引用
earth.details();
let mars = Planet::Mars(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 5 個引用
mars.details();
let jupiter = Planet::Jupiter(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 6 個引用
jupiter.details();
// TODO
let saturn = Planet::Saturn(Rc::new(Sun {}));
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 7 個引用
saturn.details();
// TODO
let uranus = Planet::Uranus(Rc::new(Sun {}));
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 8 個引用
uranus.details();
// TODO
let neptune = Planet::Neptune(Rc::new(Sun {}));
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 9 個引用
neptune.details();
assert_eq!(Rc::strong_count(&sun), 9);
drop(neptune);
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 8 個引用
drop(uranus);
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 7 個引用
drop(saturn);
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 6 個引用
drop(jupiter);
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 5 個引用
drop(mars);
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 4 個引用
// TODO
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 3 個引用
// TODO
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
println!("引用計數 = {}", Rc::strong_count(&sun)); // 2 個引用
// TODO
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
println!("引用計數 = {}", Rc::strong_count(&sun)); // 1 個引用
assert_eq!(Rc::strong_count(&sun), 1);
}