Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix typos #200

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("你好,巨集我叫做{}!", stringify!(#name));
println!("你好,巨集我叫做{}!", stringify!(#name));
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("你好,巨集我叫做{}!", stringify!(#name));
println!("你好,巨集我叫做{}!", stringify!(#name));
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/ch10-02-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

### 為型別實作特徵

現在我們已經用 `Summary` 特徵定義了所需的方法簽名。我們可以在我們多媒體聚集器的型別中實作它。範例 10-13 顯示了 `NewsArticle` 結構體實作 `Summary` 特徵的方式,其使用頭條、作者、位置來建立 `summerize` 的回傳值。至於結構體 `Tweet`,我們使用使用者名稱加上整個推文的文字來定義 `summarize`,因為推文的內容長度已經被限制在 280 個字元以內了。
現在我們已經用 `Summary` 特徵定義了所需的方法簽名。我們可以在我們多媒體聚集器的型別中實作它。範例 10-13 顯示了 `NewsArticle` 結構體實作 `Summary` 特徵的方式,其使用頭條、作者、位置來建立 `summarize` 的回傳值。至於結構體 `Tweet`,我們使用使用者名稱加上整個推文的文字來定義 `summarize`,因為推文的內容長度已經被限制在 280 個字元以內了。

<span class="filename">檔案名稱:src/lib.rs</span>

Expand Down
2 changes: 1 addition & 1 deletion src/ch15-06-reference-cycles.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## 參考循環會導致記憶體泄漏

意外情況下,執行程式時可能會產生永遠不會被清除的記憶體(通稱為**記憶體泄漏/memory leak**)。Rust 的記憶體安全性雖然可以保證令這種情況難以發生,但並非絕不可能。雖然 Rust 在編譯時可以保證做到禁止資料競爭(**data races**),但它無法保證完全避免記憶體泄漏,這是因為對 Rust 來說,記憶體泄漏是屬於安全範疇內的(**memory safe**)。透過使用 `Rc<T>` 和 `RefCell<T>` ,我們能觀察到 Rust 允許使用者自行產生記憶體泄漏:因為使用者可以產生兩個參考並互相參照,造成一個循環。這種情況下會導致記憶體泄漏,因為循環中的參考計數永遠不會變成 0,所以數值永遠不會被釋放。
意外情況下,執行程式時可能會產生永遠不會被清除的記憶體(通稱為**記憶體泄漏/memory leak**)。Rust 的記憶體安全性雖然可以保證令這種情況難以發生,但並非絕不可能。雖然 Rust 在編譯時可以保證做到禁止資料競爭(**data races**),但它無法保證完全避免記憶體泄漏,這是因為對 Rust 來說,記憶體泄漏是屬於安全範疇內的(**memory safe**。透過使用 `Rc<T>` 和 `RefCell<T>` ,我們能觀察到 Rust 允許使用者自行產生記憶體泄漏:因為使用者可以產生兩個參考並互相參照,造成一個循環。這種情況下會導致記憶體泄漏,因為循環中的參考計數永遠不會變成 0,所以數值永遠不會被釋放。

### 產生參考循環

Expand Down
2 changes: 1 addition & 1 deletion src/ch19-01-unsafe-rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Rust 的全域變數稱做**靜態**變數。範例 19-9 展示了宣告並使

<span class="caption">範例 19-10:讀取與寫入可變的靜態變數為不安全的操作</span>

與普通變數一樣,我們透過 `mut` 關鍵字指明可變性。任何讀寫 `COURTER` 的程式碼皆必須在 `unsafe` 區塊中。這個程式碼會編譯並打印出我們預期中的 `COUNTER: 3` 是因為他在單執行緒執行,若在多執行緒存取 `COUTER` 則可能導致資料競爭。
與普通變數一樣,我們透過 `mut` 關鍵字指明可變性。任何讀寫 `COURTER` 的程式碼皆必須在 `unsafe` 區塊中。這個程式碼會編譯並打印出我們預期中的 `COUNTER: 3` 是因為他在單執行緒執行,若在多執行緒存取 `COUNTER` 則可能導致資料競爭。

當能從全域存取可變資料時,確保沒有資料競爭就不容易了,這就是為什麼 Rust 將可變的靜態變數視為不安全。若是可能的話,我們推薦使用第十六章討論的並行技術與執行緒安全(thread-safe)的智慧指標(smart pointer),如此一來編譯器就能檢查從不同執行緒存取資料是安全的。

Expand Down
2 changes: 1 addition & 1 deletion src/ch19-02-advanced-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ Rust 並沒有限制不同特徵之間不能有同名的方法,也沒有阻止

因為 `Wrapper` 是一個元組結構體而 `Vec<T>` 是該元組在索引 0 上的項目,所以該 `Display` 的實作使用 `self.0` 存取內部的 `Vec<T>`。我們就可以在 `Wrapper` 上使用 `Display` 的功能了。

使用這個技術的缺點是 `Wrapper` 是個新型別,並無它封裝的值所擁有的方法。我們不得不在 `Wapper` 上實作所有 `Vec<T>` 的方法,委派這些方法給 `self.0`,讓我們可以將 `Wrapper` 作為 `Vec<T>` 一樣對待。如果我們想要新型別得到所有內部型別擁有的所有方法,一個解法是透過對 `Wrapper` 實作 `Deref` 特徵(在第十五章[「透過 `Deref` 特徵將智慧指標視為一般參考」][智慧指標取值]一節有相應討論)並回傳內部型別。如果我們不想要 `Wrapper` 擁有所有內部型別的方法,例如限制 `Wrapper` 型別之行為,就僅須實作那些我們想要的方法。
使用這個技術的缺點是 `Wrapper` 是個新型別,並無它封裝的值所擁有的方法。我們不得不在 `Wrapper` 上實作所有 `Vec<T>` 的方法,委派這些方法給 `self.0`,讓我們可以將 `Wrapper` 作為 `Vec<T>` 一樣對待。如果我們想要新型別得到所有內部型別擁有的所有方法,一個解法是透過對 `Wrapper` 實作 `Deref` 特徵(在第十五章[「透過 `Deref` 特徵將智慧指標視為一般參考」][智慧指標取值]一節有相應討論)並回傳內部型別。如果我們不想要 `Wrapper` 擁有所有內部型別的方法,例如限制 `Wrapper` 型別之行為,就僅須實作那些我們想要的方法。

現在,你知道如何將新型別模式與特徵相關聯,縱使不涉及特徵,新型別模式仍非常實用。接下來我們將目光轉移到其他與 Rust 型別系統互動的方法吧。

Expand Down
4 changes: 2 additions & 2 deletions src/ch19-03-advanced-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Rust 有一個特殊的型別叫做 `!`,由於它沒有任何值,在型別
{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-08-match-arms-different-types/src/main.rs:here}}
```

這段程式碼中 `guess` 的型別必須是**同時是**整數與字串,並且 Rust 要求 `guess` 只能是一種型別。那 `contiunue` 回傳了什麼?範例 19-26 中,為什麼允許一個分支回傳 `u32` 但同時有另一分支結束在 `continue`?
這段程式碼中 `guess` 的型別必須是**同時是**整數與字串,並且 Rust 要求 `guess` 只能是一種型別。那 `continue` 回傳了什麼?範例 19-26 中,為什麼允許一個分支回傳 `u32` 但同時有另一分支結束在 `continue`?


如你所猜,`continue` 具有 `!` 值。意即當 Rust 根據兩個分支來推算 `guess` 型別時,會觀察到前者會是 `u32`,而後者是 `!`。因為 `!` 永遠不會有值,Rust 於是決定 `guess` 的型別為 `u32`。
Expand All @@ -123,7 +123,7 @@ Rust 有一個特殊的型別叫做 `!`,由於它沒有任何值,在型別

### 動態大小型別與 `Sized` 特徵

Rust 需要了解其型別的特定細節,例如需替特定型別之值配置多少空間。這導致型別系統有令人困惑的小地方:即是**動態大小型別**(dynamically sized type)的概念。有時稱為 *DST* 或**不定大小(unsize)型別**,這些型別賦予我們寫出僅能在執行期(runtime)得知值的大小之程式碼。
Rust 需要了解其型別的特定細節,例如需替特定型別之值配置多少空間。這導致型別系統有令人困惑的小地方:即是**動態大小型別**(dynamically sized type)的概念。有時稱為 *DST* 或**不定大小(unsized)型別**,這些型別賦予我們寫出僅能在執行期(runtime)得知值的大小之程式碼。

讓我們深入研究一個貫穿全書到處使用的動態大小型別 `str` 的細節。你沒看錯,不是 `&str` 而是 `str` 本身就是 DST。在執行期前我們無從得知字串多長,也就表示無法建立一個型別為 `str` 的變數,更不能將 `str` 型別作為引數。試想以下不能執行的程式碼:

Expand Down
4 changes: 2 additions & 2 deletions src/ch19-05-macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub fn some_name(input: TokenStream) -> TokenStream {

### 如何撰寫自訂的 `derive` 巨集

我們建立一個 `hello_macro` crate,並定義 `HelloMacro` 特徵與它的 `hello_macro` 關聯函式。我們提供一個程序式巨集,讓 crate 的使用者透過 `#[derive(HelloMacro)]` 標註它們的型別,來獲得預設的 `hello_macro` 函式的實作,而不需要使用者替每個型別手動實作 `HelloMacro` 特徵。這個預設的函式實作會印出 `你好,巨集我叫做型別名稱!`,其中 `型別名稱` 是實作特徵那個型別的名字。換句話說,就是我們會寫出一個 crate,讓其他程式設計師用我們的 crate,以範例 19-30 的方式來寫程式。
我們建立一個 `hello_macro` crate,並定義 `HelloMacro` 特徵與它的 `hello_macro` 關聯函式。我們提供一個程序式巨集,讓 crate 的使用者透過 `#[derive(HelloMacro)]` 標註它們的型別,來獲得預設的 `hello_macro` 函式的實作,而不需要使用者替每個型別手動實作 `HelloMacro` 特徵。這個預設的函式實作會印出 `你好,巨集我叫做型別名稱!`,其中 `型別名稱` 是實作特徵那個型別的名字。換句話說,就是我們會寫出一個 crate,讓其他程式設計師用我們的 crate,以範例 19-30 的方式來寫程式。

<span class="filename">檔案名稱:src/main.rs</span>

Expand Down Expand Up @@ -212,7 +212,7 @@ DeriveInput {

`quote!` 巨集也提供非常炫的模板機制:我們可以輸入 `#name`,而 `quote!` 會以變數 `name` 值取而代之。我們甚至可以做一些類似普通巨集的重複工作。閱讀 [`quote` crate 的文件][quote-docs]以獲得完整的介紹。

我們想要我們的程序式巨集對使用者標註的型別產生 `HelloMacro` 特徵的實作,這個標註的型別名稱可以從 `#name` 取得。這個特徵的實作有一個函式 `hello_macro`,函式本體包含我們想要的功能:印出 `你好,巨集我叫做` 再加上被標註的型別的名稱。
我們想要我們的程序式巨集對使用者標註的型別產生 `HelloMacro` 特徵的實作,這個標註的型別名稱可以從 `#name` 取得。這個特徵的實作有一個函式 `hello_macro`,函式本體包含我們想要的功能:印出 `你好,巨集我叫做` 再加上被標註的型別的名稱。

`stringify!` 巨集是 Rust 內建的,會將一個 Rust 表達式,例如 `1 + 2`,在編譯期轉換成字串字面值(string literal),例如 `"1 + 2"`。這和 `format!` 或 `println!` 巨集會對表達式求值並將結果轉為 `String` 不同。因為輸入的 `#name` 可能是一個表達式,但要直接照字面印出來,所以我們選擇使用 `stringify!`。使用 `stringify!` 也可以節省在編譯器因為轉換 `#name` 成為字串字面量所需的空間配置。

Expand Down