You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust代码优化:如何避免循环中clone Vec<i32>以转移所有权?

如何在Rust中避免克隆Vec,直接转移所有权?

问题背景

现有Rust代码功能正常,但循环内的x.v.clone()操作存在性能浪费——因为后续会调用self.a.clear(),原向量不再被使用,理论上可以直接转移self.a[i].v的所有权到新的AStruct中,无需克隆。但移除clone后代码无法编译,需要找到可行的优化方案。

原代码:

use std::collections::HashMap;

#[derive(Debug)]
struct AStruct {
    v: Vec<i32>,
    w: i32,
}

struct TestStruct {
    a: Vec<AStruct>,
}

impl TestStruct {
    fn test(&mut self) {
        let mut h: HashMap<Vec<i32>, i32> = HashMap::new();
        for x in &self.a {
            let key = x.v.clone();
            let entry = h.entry(key).or_insert(0);
            *entry += x.w;
        }
        self.a.clear();
        for (key, value) in h {
            self.a.push( AStruct {
                v: key,
                w: value,
            } );
        }
    }
}

fn main() {
    let a = AStruct {
        v: vec![1, 2, 3],
        w: 4,
    };
    let mut t = TestStruct { a: vec![a] };
    t.test();
    println!("{:?}", t.a);
}

解决方案:取出元素所有权而非借用

核心是利用Rust集合的所有权转移方法,直接获取self.a中元素的所有权,避免克隆。推荐两种方式:

方法1:使用Vec::drain()

drain()会返回一个迭代器,获取指定范围内所有元素的所有权,迭代完成后原向量会被自动清空,正好匹配我们后续要调用clear()的场景:

use std::collections::HashMap;

#[derive(Debug)]
struct AStruct {
    v: Vec<i32>,
    w: i32,
}

struct TestStruct {
    a: Vec<AStruct>,
}

impl TestStruct {
    fn test(&mut self) {
        let mut h: HashMap<Vec<i32>, i32> = HashMap::new();
        // 用drain(..)取出所有元素的所有权,原self.a迭代后自动清空
        for x in self.a.drain(..) {
            // 直接转移x.v的所有权到HashMap的key,无需克隆
            let entry = h.entry(x.v).or_insert(0);
            *entry += x.w;
        }
        // 无需再手动调用clear()
        for (key, value) in h {
            self.a.push(AStruct {
                v: key,
                w: value,
            });
        }
    }
}

fn main() {
    let a = AStruct {
        v: vec![1, 2, 3],
        w: 4,
    };
    let mut t = TestStruct { a: vec![a] };
    t.test();
    println!("{:?}", t.a);
}

方法2:使用Vec::take()

take()会将原向量替换为空向量,并返回原向量的所有权,之后可以遍历这个返回的向量处理元素:

use std::collections::HashMap;

#[derive(Debug)]
struct AStruct {
    v: Vec<i32>,
    w: i32,
}

struct TestStruct {
    a: Vec<AStruct>,
}

impl TestStruct {
    fn test(&mut self) {
        let mut h: HashMap<Vec<i32>, i32> = HashMap::new();
        // 取出原向量的所有权,self.a被替换为空向量
        let old_a = self.a.take();
        for x in old_a {
            let entry = h.entry(x.v).or_insert(0);
            *entry += x.w;
        }
        for (key, value) in h {
            self.a.push(AStruct {
                v: key,
                w: value,
            });
        }
    }
}

fn main() {
    let a = AStruct {
        v: vec![1, 2, 3],
        w: 4,
    };
    let mut t = TestStruct { a: vec![a] };
    t.test();
    println!("{:?}", t.a);
}

为什么这两种方法可行?

  • 两种方式都避免了对x.v的克隆,直接转移了Vec<i32>的所有权到HashMap中,性能更优。
  • 原向量的元素被全部取出后,自身会变为空,完全符合后续要清空的需求,无需额外调用clear()。

内容的提问来源于stack exchange,提问作者André

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:02:55