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() 方法创建值的深拷贝,保留原始所有权
相关推荐
小杍随笔13 小时前
2025年Rust GUI框架实战万字避坑指南
开发语言·后端·rust
在水一缸1 天前
当 AI 编码助手遇上 Rust:深入解析 Zerostack 的极简哲学与实战应用
rust·系统架构·开源项目·轻量化·ai编码助手·zerostack
2401_873479402 天前
风控引擎高并发IP查询方案对比:开源Rust库 vs 商业离线库,怎么选?
tcp/ip·rust·开源·ip
花褪残红青杏小2 天前
Rust图像处理第22节-从RGB到YCbCr: 让亮度和颜色分家
rust·webassembly·图形学
花褪残红青杏小2 天前
Rust图像处理第21节-最小二乘回归:用矩阵求逆解"拟合"问题
rust·webassembly·图形学
k4m7v2pz2 天前
Bevy 0.14.2 玩家精灵不渲染(只有背景在动)排查全记录
macos·rust·bevy
老王生涯3 天前
rust开发环境配置-Windows & GNU
开发语言·windows·rust
Yeauty3 天前
自建 HLS 第一问:fMP4 还是 TS?用 Rust 在进程内把两种都跑出来
开发语言·后端·rust
Flynt3 天前
我用Biome替换ESLint+Prettier在项目上踩了不少坑
rust·eslint·前端工程化
Yeauty3 天前
2026 年在 Rust 里处理音视频,该走哪条路?
rust·ffmpeg·音视频·视频