Skip to main content

所有權與作用域 (Ownership and Scope)

Move 中的每個變數都有一個作用域 (Scope) 和一個所有者 (Owner)。作用域是變數有效的程式碼範圍,而所有者是該變數所屬的作用域。一旦所有者作用域結束,變數就會被丟棄 (dropped)。這是 Move 中的一個核心概念,瞭解其運作方式非常重要。

所有權 (Ownership)

在函式作用域中定義的變數歸該作用域所有。執行時期會遍歷函式作用域並執行每個表達式和語句。函式作用域結束後,其中定義的變數會被丟棄或釋放。

module book::ownership;

public fun owner() {
let a = 1; // a 歸 `owner` 函式所有
} // a 在此處被丟棄

public fun other() {
let b = 2; // b 歸 `other` 函式所有
} // b 在此處被丟棄

#[test]
fun test_owner() {
owner();
other();
// a 和 b 在此處無效
}

在上面的範例中,變數 aowner 函式所有,變數 bother 函式所有。當呼叫這些函式中的每一個時,變數被定義;當函式結束時,變數被丟棄。

傳回值 (Returning a Value)

如果我們更改 owner 函式以傳回變數 a,則 a 的所有權將轉移給該函式的呼叫者。

module book::ownership;

public fun owner(): u8 {
let a = 1; // a 在此處定義
a // 作用域結束,a 被傳回
}

#[test]
fun test_owner() {
let a = owner();
// a 在此處有效
} // a 在此處被丟棄

按值傳遞 (Passing by Value)

此外,如果我們將變數 a 傳遞給另一個函式,a 的所有權將轉移給該函式。在執行此操作時,我們將值從一個作用域 移動 (move) 到另一個作用域。這也被稱為 移動語意 (move semantics)

module book::ownership;

public fun owner(): u8 {
let a = 10;
a
} // a 被傳回

public fun take_ownership(v: u8) {
// v 歸 `take_ownership` 所有
} // v 在此處被丟棄

#[test]
fun test_owner() {
let a = owner();
// `u8` 是可複製的,呼叫函式時使用 `move a` 以強制轉移其所有權
take_ownership(move a);
// a 在此處無效
}

區塊作用域 (Scopes with Blocks)

每個函式都有一個主作用域,它也可以透過使用區塊 (blocks) 擁有子作用域。區塊是一系列的語句和表達式,它有自己的作用域。在區塊中定義的變數歸該區塊所有,當區塊結束時,變數被丟棄。

module book::ownership;

public fun owner() {
let a = 1; // a 歸 `owner` 函式的作用域所有
{
let b = 2; // 宣告 b 的區塊擁有它
{
let c = 3; // 宣告 c 的區塊擁有它
}; // c 在此處被丟棄
}; // b 在此處被丟棄
// a = b; // 錯誤:b 在此處無效
// a = c; // 錯誤:c 在此處無效
} // a 在此處被丟棄

發但也,如果我們從區塊中傳回一個值,則變數的所有權將轉移給該區塊的呼叫者。

module book::ownership;

public fun owner(): u8 {
let a = 1; // a 歸 `owner` 函式的作用域所有
let b = {
let c = 2; // 宣告 c 的區塊擁有它
c // c 從區塊中傳回並轉移給 b
};
a + b // a 和 b 在此處均有效
}

可複製類型 (Copyable Types)

Move 中的某些類型是 可複製的 (copyable),這意味著它們可以被複製而無需轉移所有權。這對於體積小且複製成本低的類型(如整數和布林值)非常有用。當這些類型被傳遞給函式、從函式傳回,或者當它們被「移動」到另一個作用域然後在其原始作用域中被存取時,Move 編譯器會自動複製這些類型。

延伸閱讀