← 返回首页

FIELD NOTE / 2026-08-15

rust语法

rustlings智能指针之cow

`Cow` 可以暂时借用数据,只有在确实需要修改时,才把借用的数据克隆成自有数据。

这个练习介绍 CowClone-On-Write(写时复制)

Cow 可以暂时借用数据,只有在确实需要修改时,才把借用的数据克隆成自有数据。

需要填写的答案

三个 todo!() 分别是:

// reference_no_mutation
Cow::Borrowed(_)

// owned_no_mutation
Cow::Owned(_)

// owned_mutation
Cow::Owned(_)

因此测试部分应为:

#[test]
fn reference_no_mutation() {
    let vec = vec![0, 1, 2];
    let mut input = Cow::from(&vec);
    abs_all(&mut input);

    assert!(matches!(input, Cow::Borrowed(_)));
}

#[test]
fn owned_no_mutation() {
    let vec = vec![0, 1, 2];
    let mut input = Cow::from(vec);
    abs_all(&mut input);

    assert!(matches!(input, Cow::Owned(_)));
}

#[test]
fn owned_mutation() {
    let vec = vec![-1, 0, 1];
    let mut input = Cow::from(vec);
    abs_all(&mut input);

    assert!(matches!(input, Cow::Owned(_)));
}

Cow<[i32]> 的两种状态

Cow<'a, [i32]>

主要有两种形式:

Cow::Borrowed(&[i32])
Cow::Owned(Vec<i32>)

也就是说,它既可以保存借用的切片,也可以保存自己拥有的 Vec<i32>

abs_all 的工作方式

fn abs_all(input: &mut Cow<[i32]>) {
    for ind in 0..input.len() {
        let value = input[ind];

        if value < 0 {
            input.to_mut()[ind] = -value;
        }
    }
}

这段代码把所有负数转换成正数。

关键是:

input.to_mut()

to_mut() 会返回一个可变引用:

  • 如果当前是 Cow::Owned,直接返回内部 Vec
  • 如果当前是 Cow::Borrowed,先克隆借用的数据,再转成 Cow::Owned
  • 如果没有调用 to_mut(),就不会发生克隆

四个测试的状态变化

1. 借用数据,并且需要修改

let vec = vec![-1, 0, 1];
let mut input = Cow::from(&vec);
abs_all(&mut input);

初始状态:

Cow::Borrowed(&vec)

发现 -1,需要修改。由于原始 vec 只是借用的,不能直接修改,因此 to_mut() 会执行克隆:

Borrowed -> Owned

所以结果是:

Cow::Owned(_)

原始 vec 不会被改变。


2. 借用数据,但不需要修改

let vec = vec![0, 1, 2];
let mut input = Cow::from(&vec);
abs_all(&mut input);

所有元素都已经是非负数,因此这段代码永远不会执行:

input.to_mut()[ind] = -value;

所以不会发生克隆,状态保持:

Borrowed -> Borrowed

结果是:

Cow::Borrowed(_)

3. 一开始就拥有数据,且不需要修改

let vec = vec![0, 1, 2];
let mut input = Cow::from(vec);

这里没有使用 &,所以 Vec 的所有权直接移动进 Cow

Cow::Owned(vec)

即使后续没有修改,也不会变成 Borrowed,因为它从一开始就是拥有数据的:

Owned -> Owned

4. 一开始就拥有数据,且需要修改

let vec = vec![-1, 0, 1];
let mut input = Cow::from(vec);

初始状态已经是:

Cow::Owned(vec)

调用 to_mut() 时,直接取得内部 Vec 的可变引用,不需要再次克隆:

Owned -> Owned

结果仍然是:

Cow::Owned(_)

matches! 的含义

例如:

assert!(matches!(input, Cow::Borrowed(_)));

表示检查 input 是否匹配:

Cow::Borrowed(...)

其中 _ 表示忽略内部具体内容。

类似地:

assert!(matches!(input, Cow::Owned(_)));

表示检查它是否拥有内部的 Vec<i32>

这个练习的核心规律是:

初始数据是否需要修改最终状态
借用数据Cow::Owned
借用数据Cow::Borrowed
自有数据Cow::Owned
自有数据Cow::Owned

Cow 的优势就是:只在必要时复制数据,避免不必要的克隆。