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() 方法创建值的深拷贝,保留原始所有权
相关推荐
ServBay1 天前
这9个高性能的Rust库不容错过
后端·rust
Rust研习社1 天前
Rust 堆内存指针 Box 详解
开发语言·后端·rust
Jacky-0081 天前
Rust安装(MinGw64编译器安装)
开发语言·后端·rust
咚为2 天前
深入理解 Rust 的静态分发与动态分发:从 `impl Trait` 到 `dyn Trait`
开发语言·后端·rust
中国胖子风清扬2 天前
基于GPUI框架构建现代化待办事项应用:从架构设计到业务落地
java·spring boot·macos·小程序·rust·uni-app·web app
爱分享的阿Q2 天前
RustWebAssembly商用元年从实验到生产完整迁移指南
rust·web·wasm
大卫小东(Sheldon)2 天前
Rudist v0.5.1 发布:AI 驱动的 Redis 客户端,更快、更直观
rust·rudist
潇洒畅想2 天前
1.2 希腊字母速查表 + 公式阅读实战
java·人工智能·python·算法·rust·云计算
刘彬_bing3 天前
Rust 锁的终极指南:为什么标准库不够用?第三方锁如何拯救你的并发性能!
rust