rustlings 学习笔记 -- exercises/06_move_semantics

exercises/06_move_semantics

move_semantics1.rs - 基础移动语义

问题代码

rust 复制代码
// TODO: Fix the compiler error in this function.
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    let vec = vec;

    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics1() {
        let vec0 = vec![22, 44, 66];
        let vec1 = fill_vec(vec0);
        assert_eq!(vec1, vec![22, 44, 66, 88]);
    }
}

解题要点

  • 错误原因 : 函数参数 vec 已经移动到函数内部,不需要重新赋值
  • 解决方法 : 直接使用参数 vec,去掉多余的重新赋值

正确写法

rust 复制代码
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics1() {
        let vec0 = vec![22, 44, 66];
        let vec1 = fill_vec(vec0);
        assert_eq!(vec1, vec![22, 44, 66, 88]);
    }
}

move_semantics2.rs - 所有权保留

问题代码

rust 复制代码
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    let mut vec = vec;

    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    // TODO: Make both vectors `vec0` and `vec1` accessible at the same time to
    // fix the compiler error in the test.
    #[test]
    fn move_semantics2() {
        let vec0 = vec![22, 44, 66];

        let vec1 = fill_vec(vec0);

        assert_eq!(vec0, [22, 44, 66]);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}

解题要点

  • 错误原因 : vec0 被移动到 fill_vec 函数后,在测试中无法再使用
  • 解决方法 : 传递 vec0 的引用而不是所有权,或者克隆向量

正确写法

rust 复制代码
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    let mut vec = vec;

    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics2() {
        let vec0 = vec![22, 44, 66];

        let vec1 = fill_vec(vec0.clone());

        assert_eq!(vec0, [22, 44, 66]);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}

move_semantics3.rs - 可变绑定

问题代码

rust 复制代码
// TODO: Fix the compiler error in the function without adding any new line.
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics3() {
        let vec0 = vec![22, 44, 66];
        let vec1 = fill_vec(vec0);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}

解题要点

  • 错误原因 : 函数参数 vec 是不可变的,但 push 方法需要可变引用
  • 解决方法 : 将参数声明为可变的 let mut vec = vec

正确写法

rust 复制代码
fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> {
    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics3() {
        let vec0 = vec![22, 44, 66];
        let vec1 = fill_vec(vec0);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}

move_semantics4.rs - 可变引用冲突

问题代码

rust 复制代码
fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    // TODO: Fix the compiler errors only by reordering the lines in the test.
    // Don't add, change or remove any line.
    #[test]
    fn move_semantics4() {
        let mut x = Vec::new();
        let y = &mut x;
        let z = &mut x;
        y.push(42);
        z.push(13);
        assert_eq!(x, [42, 13]);
    }
}

解题要点

  • 错误原因 : 同时存在两个可变引用 yz 指向同一个数据,违反借用规则
  • 解决方法: 重新排列代码,确保同一时间只有一个可变引用

正确写法

rust 复制代码
fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    #[test]
    fn move_semantics4() {
        let mut x = Vec::new();
        let y = &mut x;
        y.push(42);
        let z = &mut x;
        z.push(13);
        assert_eq!(x, [42, 13]);
    }
}

move_semantics5.rs - 引用与所有权

问题代码

rust 复制代码
#![allow(clippy::ptr_arg)]

// TODO: Fix the compiler errors without changing anything except adding or
// removing references (the character `&`).

// Shouldn't take ownership
fn get_char(data: String) -> char {
    data.chars().last().unwrap()
}

// Should take ownership
fn string_uppercase(mut data: &String) {
    data = data.to_uppercase();

    println!("{data}");
}

fn main() {
    let data = "Rust is great!".to_string();

    get_char(data);

    string_uppercase(&data);
}

解题要点

  • 错误原因 : get_char 不应该获取所有权,应该使用引用;string_uppercase 的参数类型错误
  • 解决方法: 调整函数参数的引用类型

正确写法

rust 复制代码
#![allow(clippy::ptr_arg)]

// Shouldn't take ownership
fn get_char(data: &String) -> char {
    data.chars().last().unwrap()
}

// Should take ownership
fn string_uppercase(mut data: String) {
    data = data.to_uppercase();

    println!("{data}");
}

fn main() {
    let data = "Rust is great!".to_string();

    get_char(&data);

    string_uppercase(data);
}

知识点汇总

移动语义基础

  • 所有权转移: 当值赋给另一个变量时,所有权会发生移动
  • 函数参数: 传递给函数的值会被移动,除非使用引用
  • 返回值: 函数返回值可以转移所有权给调用者

可变性与借用

  • 可变绑定 : 使用 mut 关键字声明可变变量
  • 可变引用 : 使用 &mut 创建可变引用,用于修改数据
  • 借用规则: 同一时间只能有一个可变引用或多个不可变引用

引用类型

  • 不可变引用 : 使用 &T 创建不可变引用,不转移所有权
  • 可变引用 : 使用 &mut T 创建可变引用,用于修改数据
  • 克隆 : 使用 .clone() 方法创建值的深拷贝,保留原始所有权
相关推荐
ssshooter5 小时前
Tauri 踩坑 appLink 修改后闪退
前端·ios·rust
布列瑟农的星空6 小时前
前端都能看懂的rust入门教程(二)——函数和闭包
前端·后端·rust
蚂蚁背大象1 天前
Rust 所有权系统是为了解决什么问题
后端·rust
布列瑟农的星空1 天前
前端都能看懂的rust入门教程(五)—— 所有权
rust
Java水解2 天前
Rust嵌入式开发实战——从ARM裸机编程到RTOS应用
后端·rust
Pomelo_刘金2 天前
Rust:所有权系统
rust
Ranger09292 天前
鸿蒙开发新范式:Gpui
rust·harmonyos
DongLi015 天前
rustlings 学习笔记 -- exercises/05_vecs
rust
番茄灭世神6 天前
Rust学习笔记第2篇
rust·编程语言