Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split a Vec into two without allocating memory?

I am looking for a function similar to slice::split_at_mut. Let's name it split_at with the signature

pub fn split_at<T>(v: Vec<T>, mid: usize) -> (Vec<T>, Vec<T>)

such that

let v = vec![1, 2, 3, 4];
let (first, second) = split_at(v, 2);
assert_eq!(first, vec![1, 2]);
assert_eq!(second, vec![3, 4]);

The function should allocate no memory and simply split a vector into two. You don't need to worry about capacity as the resultant vectors will not be modified.

The nightly-only method Vec::into_raw_parts seems promising, but I am on the stable release channel which doesn't allow such methods.

like image 289
nalzok Avatar asked Apr 18 '26 16:04

nalzok


2 Answers

Your request, as phrased, is not possible with a Vec. Vec represents unique ownership of the allocated memory. When a Vec goes out of scope, that memory will be deallocated.

If you could do what you ask, then you'd either

  1. Deallocate one piece of memory twice (the starting piece of memory)
  2. Deallocate a non-allocated piece of memory (somewhere in the middle of the memory)

Both cases are memory unsafety, exactly what Rust aims to prevent.


You are likely coming from a programming language with a garbage collector, and that's also a way to solve the same problem here.

The bytes crate provides a reference-counted vector-like type called Bytes (or BytesMut for other circumstances):

use bytes::Bytes; // 1.0.1

fn main() {
    let v = Bytes::from(vec![1, 2, 3, 4]);
    let (first, second) = v.split_at(2);
    assert_eq!(first, vec![1, 2]);
    assert_eq!(second, vec![3, 4]);
}
like image 162
Shepmaster Avatar answered Apr 20 '26 05:04

Shepmaster


Not exactly what I was looking for, but split_off is close enough.

let mut vec = vec![1, 2, 3];
let vec2 = vec.split_off(1);
assert_eq!(vec, [1]);
assert_eq!(vec2, [2, 3]);

To answer my own question

pub fn split_at<T>(mut v: Vec<T>, mid: usize) -> (Vec<T>, Vec<T>) {
    let remainder = v.split_off(mid);
    (v, remainder)
}
like image 22
nalzok Avatar answered Apr 20 '26 05:04

nalzok



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!