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

如何将Vec拆分为指定索引元素与剩余向量的可变引用元组?

Rust实现split_rest_mut:同时获取元素可变引用与剩余元素

首先需要明确:Rust的切片(&mut [T])必须指向连续内存块。原数组去掉中间元素后,剩余元素在内存中不连续,因此无法用单个可变切片表示。你示例中的[1,2,4,5,6]是逻辑上的剩余集合,无法直接对应到实际的Rust切片。

下面给出高性能的实现,通过unsafe代码绕过借用检查(手动保证内存安全),返回目标元素的可变引用,以及前后两个不重叠的剩余切片:

核心实现

use std::slice;

/// 扩展切片,提供获取指定位置元素及剩余前后切片的方法
trait SplitRestMut {
    type Item;
    fn split_rest_mut(&mut self, index: usize) -> (&mut Self::Item, &mut [Self::Item], &mut [Self::Item]);
}

impl<T> SplitRestMut for [T] {
    type Item = T;
    fn split_rest_mut(&mut self, index: usize) -> (&mut T, &mut [T], &mut [T]) {
        // 索引合法性检查,避免越界
        assert!(index < self.len(), "split_rest_mut: index out of bounds");
        
        let len = self.len();
        let ptr = self.as_mut_ptr();
        
        unsafe {
            // 获取目标位置的可变引用
            let item = &mut *ptr.add(index);
            // 前半部分切片:0..index
            let left = slice::from_raw_parts_mut(ptr, index);
            // 后半部分切片:index+1..len
            let right = slice::from_raw_parts_mut(ptr.add(index + 1), len - index - 1);
            
            (item, left, right)
        }
    }
}

使用示例

#[derive(Debug)]
struct Item(i32);

impl Item {
    fn do_something(&mut self, left: &mut [Item], right: &mut [Item]) {
        // 修改当前元素
        self.0 *= 2;
        // 修改左侧剩余元素
        left.iter_mut().for_each(|item| item.0 += 1);
        // 修改右侧剩余元素
        right.iter_mut().for_each(|item| item.0 -= 1);
    }
}

fn main() {
    let mut model = vec![Item(1), Item(2), Item(3), Item(4), Item(5), Item(6)];
    
    for index in 0..model.len() {
        let (item, left, right) = model.split_rest_mut(index);
        item.do_something(left, right);
    }
    
    println!("处理后结果: {:?}", model);
}

性能说明

这个实现是零开销的:

  • 仅包含指针偏移、内存检查(assert)和切片构造,无内存分配或复制;
  • unsafe代码的使用是安全的:三个可变引用指向完全不重叠的内存区域,索引检查避免越界,引用生命周期与原切片绑定,不会出现悬垂引用。

可选:封装剩余元素迭代器

如果需要将剩余元素作为一个逻辑连续的集合遍历,可以基于前后切片封装迭代器:

struct RestIter<'a, T> {
    left: std::slice::IterMut<'a, T>,
    right: std::slice::IterMut<'a, T>,
}

impl<'a, T> Iterator for RestIter<'a, T> {
    type Item = &'a mut T;
    
    fn next(&mut self) -> Option<Self::Item> {
        self.left.next().or_else(|| self.right.next())
    }
}

// 为SplitRestMut trait添加迭代器方法
impl<T> SplitRestMut for [T] {
    // 保留原有方法...
    
    fn split_rest_iter_mut(&mut self, index: usize) -> (&mut Self::Item, RestIter<'_, Self::Item>) {
        let (item, left, right) = self.split_rest_mut(index);
        (item, RestIter {
            left: left.iter_mut(),
            right: right.iter_mut(),
        })
    }
}

使用迭代器的示例:

impl Item {
    fn do_something_with_iter(&mut self, rest: impl Iterator<Item = &mut Item>) {
        self.0 *= 2;
        rest.for_each(|item| item.0 += 5);
    }
}

// 在main函数中替换循环:
for index in 0..model.len() {
    let (item, rest_iter) = model.split_rest_iter_mut(index);
    item.do_something_with_iter(rest_iter);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 04:20:55