Rust 中 *、&、mut、&mut、ref、ref mut 的用法和區別

日升_rs發表於2024-07-25

Rust 中 *、&、mut、&mut、ref、ref mut 的用法和區別

Rust 中,*refmut&ref mut 是用於處理引用、解引用和可變性的關鍵字和運算子,它們在不同的上下文中有不同的用法。

一、* 解引用

* 屬於運算子

1. 作用

用於解引用指標或引用,以訪問其指向的值。
透過解引用,可以從指標或引用中獲取實際的值。

2. 用法

2.1. 解引用不可變引用

fn main() {
	let x = 5;
	let y = &x; // y 是對 x 的不可變引用
	println!("y: {}", *y); // 透過解引用 y 獲取 x 的值,輸出: y: 5
}

2.2. 解引用可變引用

fn main() {
	let mut x = 10;
    let y = &mut x; // y 是對 x 的可變引用
    *y += 5; // 透過解引用 y 修改 x 的值
    println!("x: {}", x); // 輸出: x: 15
}

2.3. 解引用指標

fn main() {
	let x = 42;
    let y = &x as *const i32; // 建立不可變裸指標
    unsafe {
        println!("y: {}", *y); // 解引用不可變裸指標
    }
	
	let x = Box::new(10); // Box 智慧指標
    println!("x: {}", *x); // 解引用 Box,獲取其值,輸出: x: 10
}

二、& 借用引用

& 也是運算子

1. 作用

建立一個值的不可變引用,允許讀而不獲取所有權,該值在引用期間是隻讀的。

2. 用法

2.1. 不可變引用

fn main() {
    let x = 10;
    let y = &x; // y 是對 x 的不可變引用
    println!("y: {}", y); // 輸出: y: 10
}

2.2. 函式中的借用

fn print_value(x: &i32) {
    println!("Value: {}", x);
}

fn main() {
    let a = 10;
    print_value(&a); // 傳遞 a 的不可變引用
}

2.3. match 中使用

fn main() {
	let reference = &4;
    match reference {
        &val => println!("Got a value via destructuring: {:?}", val),
    }
}

2.4. 結構體中使用

struct Point<'a> {
    x: &'a i32,
    y: &'a i32,
}
fn main() {
    let x = 10;
    let y = 20;
    let point = Point { x: &x, y: &y }; // 使用引用初始化結構體欄位
    println!("Point: ({}, {})", point.x, point.y); // 輸出: Point: (10, 20)
}

2.5. 集合中使用

fn main() {
    let vec = vec![1, 2, 3];
    for val in &vec {
        println!("Value: {}", val); // 輸出: 1, 2, 3
    }
}

2.6. 切片中使用

fn main() {
    let s = String::from("hello");
    let slice = &s[0..2]; // 建立字串切片
    println!("Slice: {}", slice); // 輸出: Slice: he
}

三、mut 可變

mut 是一個關鍵字

1. 作用

宣告一個變數或引用為可變的,可以修改其值。

2. 用法

2.1. 可變變數

fn main() {
    let mut x = 5; // x 是可變的
    x += 1;
    println!("x: {}", x); // 輸出: x: 6
}

2.2. 函式中可變引數

fn increment(mut num: i32) -> i32 {
    num += 1;
    num
}

2.3. 可變引用

fn main() {
    let mut x = 5;
    let y = &mut x;
    *y += 1;
    println!("{}", x); // 輸出 6
}

2.4. 可變結構體

struct Point {
    x: i32,
    y: i32,
}
fn main() {
    let mut p = Point { x: 0, y: 0 };
    p.x = 5;
    p.y = 10;
    println!("Point: ({}, {})", p.x, p.y); // 輸出 Point: (5, 10)
}

2.5. 可變元組

let mut tuple = (5, 10);
tuple.0 = 15;

2.6. match 中使用

match Some(10) {
    Some(mut value) => {
        value += 1;
        println!("{}", value); // 輸出 11
    }
    None => {},
}

2.7. 集合中使用

let mut vec = vec![1, 2, 3];
for num in &mut vec {
    *num += 1;
}
println!("{:?}", vec);

四、&mut 可變借用引用

&mut 既不屬於運算子也不屬於關鍵字

1. 作用

建立一個值的可變引用,允許修改值而不獲取所有權。

2. 用法

2.1. 可變引用

fn main() {
    let mut x = 10;
    {
        let y = &mut x; // y 是對 x 的可變引用
        *y += 5; // 修改 x 的值
    } // y 的生命週期結束,此時 x 的可變借用結束
    println!("x: {}", x); // 輸出: x: 15
}

2.2. 函式中的可變引用

fn add_one(x: &mut i32) {
    *x += 1;
}

fn main() {
    let mut a = 10;
    add_one(&mut a); // 傳遞 a 的可變引用
    println!("a: {}", a); // 輸出: a: 11
}

2.3. 結構體中的可變引用

struct Point<'a> {
    x: &'a mut i32,
    y: &'a mut i32,
}
fn main() {
    let mut x = 10;
    let mut y = 20;
    let point = Point { x: &mut x, y: &mut y }; // 使用可變引用初始化結構體欄位
    *point.x += 1;
    *point.y += 1;
    println!("Point: ({}, {})", point.x, point.y); // 輸出: Point: (11, 21)
}

2.4. 集合中的可變引用

fn main() {
    let mut vec = vec![1, 2, 3];
    for val in &mut vec {
        *val += 1; // 修改集合中的元素
    }
    println!("{:?}", vec); // 輸出: [2, 3, 4]
}

2.5. match 中使用

fn main() {
    let mut pair = (10, 20);
    match pair {
        (ref mut x, ref mut y) => {
            *x += 1;
            *y += 1;
            println!("x: {}, y: {}", x, y); // 輸出: x: 11, y: 21
        },
    }
}

2.6. 結構體中使用

struct Counter {
    value: i32,
}
impl Counter {
    fn increment(&mut self) {
        self.value += 1;
    }
}
fn main() {
    let mut counter = Counter { value: 0 };
    counter.increment(); // 使用可變引用呼叫方法
    println!("Counter value: {}", counter.value); // 輸出: Counter value: 1
}

五、ref 模式匹配中建立引用

ref 屬於關鍵字

1. 作用

在模式匹配中借用值的不可變引用,而不是獲取所有權。

2. 用法

2.1. 元組中使用

fn main() {
    let tuple = (1, 2);
    let (ref x, ref y) = tuple; // x 和 y 是對 tuple 中元素的不可變引用
    println!("x: {}, y: {}", x, y); // 輸出: x: 1, y: 2
}

2.2. match 中使用

fn main() {
    let pair = (10, 20);
    match pair {
        (ref x, ref y) => {
            println!("x: {}, y: {}", x, y); // x 和 y 是 pair 元素的不可變引用
        }
    }
}

2.3. if let / while let 中使用

// if let
fn main() {
    let some_value = Some(42);
    if let Some(ref x) = some_value {
        println!("Found a value: {}", x); // x 是 some_value 的不可變引用
    }
}
// while let
fn main() {
    let mut stack = vec![1, 2, 3];
    while let Some(ref x) = stack.pop() {
        println!("Popped: {}", x); // x 是 stack 中最後一個元素的不可變引用
    }
}

2.4. 函式中使用

fn print_ref((ref x, ref y): &(i32, i32)) {
    println!("x: {}, y: {}", x, y); // x 和 y 是元組元素的不可變引用
}
fn main() {
    let pair = (10, 20);
    print_ref(&pair); // 傳遞 pair 的引用
}

2.5. for 迴圈中使用

fn main() {
    let vec = vec![1, 2, 3];
    for ref x in &vec {
        println!("x: {}", x); // x 是 vec 中元素的不可變引用
    }
}

六、ref mut 模式匹配中建立可變引用

ref mut 屬於關鍵字

1. 作用

在模式匹配中借用值的可變引用,允許修改該值。

2. 用法

2.1. match 中使用

fn main() {
    let mut pair = (10, 20);
    match pair {
        (ref mut x, ref mut y) => {
            *x += 1;
            *y += 1;
            println!("x: {}, y: {}", x, y); // 輸出: x: 11, y: 21
        }
    }
    // pair 的值已經被修改
}

2.2. if let / while let 中使用

fn main() {
    let mut some_value = Some(42);
    if let Some(ref mut x) = some_value {
        *x += 1;
        println!("Found a value: {}", x); // 輸出: Found a value: 43
    }
}
fn main() {
    let mut stack = vec![1, 2, 3];
    while let Some(ref mut x) = stack.pop() {
        *x += 1;
        println!("Popped: {}", x); // 輸出: Popped: 4, Popped: 3, Popped: 2
    }
}

2.3. 函式中使用

fn increment_tuple((ref mut x, ref mut y): &mut (i32, i32)) {
    *x += 1;
    *y += 1;
}

fn main() {
    let mut pair = (10, 20);
    increment_tuple(&mut pair); // 傳遞 pair 的可變引用
    println!("pair: {:?}", pair); // 輸出: pair: (11, 21)
}

2.4. 解構賦值

fn main() {
    let mut pair = (10, 20);
    let (ref mut x, ref mut y) = pair;
    *x += 1;
    *y += 1;
    println!("x: {}, y: {}", x, y); // 輸出: x: 11, y: 21
    println!("{:?}", pair); // (11, 21)
}

七、總結

  • *:解引用運算子,用於訪問指標或引用指向的值的型別。
  • &:借用運算子,用於建立不可變引用的型別,允許只讀訪問。
  • mut:關鍵字,用於宣告可變變數或引數的型別,允許其值被修改。
  • &mut:借用運算子,用於建立可變引用的型別,允許讀寫訪問。
  • ref:模式匹配中的關鍵字,用於建立不可變引用的型別,避免所有權轉移。
  • ref mut:模式匹配中的關鍵字,用於建立可變引用的型別,允許修改引用的值。

相關文章