I have a variable a of type &[T]; how can I get a reference to a subslice of a?
As a concrete example, I'd like to get the first and second halves of a, provided a.len() is even.
You use slicing syntax for that:
fn main() {
let data: &[u8] = b"12345678";
println!("{:?} - {:?}", &data[..data.len()/2], &data[data.len()/2..]);
}
(try it here)
The general syntax is
&slice[start_idx..end_idx]
which gives a slice derived from slice, starting at start_idx and ending at end_idx-1 (that is, item at the right index is not included). Either index could be omitted (even both), which would mean zero or slice length, correspondingly.
Note that if you want to split a slice at some position into two slices, it is often better to use split_at() method:
let data = b"12345678";
let (left, right): (&[u8], &[u8]) = data.split_at(4);
Moreover, this is the only way to obtain two mutable slices out of another mutable slice:
let mut data: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8];
let data_slice: &mut [u8] = &mut data[..];
let (left, right): (&mut [u8], &mut [u8]) = data_slice.split_at_mut(4);
However, these basic things are explained in the official book on Rust. You should start from there if you want to learn Rust.
Related
I want to iterate through a vector, and get a mutable reference to each item, and a mutable slice to the rest of the vector, so I can use both every iteration. Something like:
e.g:
for index in 0..model.len() {
let (item, rest): (&mut Item, &mut [Item]) = model.split_rest_mut(index);
item.do_something(rest);
}
e.g [1,2,3,4,5,6].split_rest_mut(2) would be 3, [1,2,4,5,6].
I would like this to be as performant as possible.
It seems to be similar behaviour to split_at_mut, so I imagine this should be possible.
How would I go about doing this?
With the exact signature split_rest_mut(usize) -> (&mut T, &[T]), that is impossible: for an index which is neither for the first element nor the last element, the remaining elements are not contiguous in memory, and so cannot coexist in a single slice.
Instead, such a function would have to return two slices: one for the leading part of the slice and another one for the trailing part.
+-------------+-------------+--------------+
| ...leading | middle item | ...trailing |
+-------------+-------------+--------------+
Its implementation can be built with a combination of split_at_mut and split_first_mut.
pub fn split_at_rest_mut<T>(x: &mut [T], index: usize) -> (&mut T, &mut [T], &mut [T]) {
assert!(index < x.len());
// split in two
let (leading, trailing) = x.split_at_mut(index);
// split second half in [value, ...rest]
let (val, trailing) = trailing.split_first_mut().unwrap();
(val, leading, trailing)
}
Using:
let mut v = vec![1, 2, 5, 7, 8, 9];
assert_eq!(
split_at_rest_mut(&mut v, 2),
(&mut 5, &mut [1, 2][..], &mut [7, 8, 9][..]),
);
Playground
It's not built in, but you can create it yourself easily enough based on Vec::split_at_mut:
fn split_rest_mut<T>(vec: &mut Vec<T>, mid: usize) -> (&mut T, &mut [T]) {
let (left, right) = vec.split_at_mut(mid);
(left.last_mut().expect("mid is 0"), right)
}
Usage:
let (item, rest): (&mut Item, &mut [Item]) = split_rest_mut(&mut model, index);
Vec::split_at_mut is somewhat special because it returns two mutable references. Its implementation guarantees that those don't refer to the same values inside the vector, but it takes unsafe code to implement it. So while you could theoretically create your own unsafe implementation of split_rest_mut, its safer to base it on split_at_mut instead.
How would I go about doing this?
Call split_at_mut and retrieve the last element of the first slice as your "current"?
Alternatively, use a slice pattern: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=67d007bac2a94ff2cdcfbf36cdc4da35
if let [head, tail#..] = &mut model[i..] {
*head += 1;
println!("{}, {:?}", head, tail);
}
edit:
e.g [1,2,3,4,5,6].split_rest_mut(2) would be 3, [1,2,4,5,6].
that's not possible. A slice is a contiguous buffer. You can have a "slice before", "focus", "slice after" using split_at_mut and split_first_mut or split_last_mut: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=14cd90a694ffcb976f6e774a96d5d2c6
fn focus<T>(s: &mut [T], i: usize) -> Option<(&mut [T], &mut T, &mut [T])> {
let (head, tail) = s.split_at_mut(i);
let (focus, tail) = tail.split_first_mut()?;
Some((head, focus, tail))
}
If you want a non-contiguous sequence you need to look at something like ndarray, and even then I'm not sure they'd have such an odd collection.
I have an fn that looks something like this:
use std::io::Read;
fn read_something(file: &mut impl Read) {
let _ = file.read(&mut [0; 8]);
}
When I pass a slice of a Vec into it like that:
fn main() {
let vector = vec![1, 2, 3, 4];
read_something(&mut &vector[..]);
}
it works fine. But when I save the slice into a variable first it does not compile:
fn main() {
let vector = vec![1, 2, 3, 4];
let slice = &vector[..];
read_something(&mut slice);
}
The compiler tells me, that I
cannot borrow as mutable
Playground
How do these two cases differ?
Why does the first example work even though the vector is not declared as mutable either?
How can I pass a &[u8] slice into that fn, that eats a &mut impl Read?
How can I pass a &[u8] slice into that fn, that eats a &mut impl Read?
Add mut to the variable that holds the slice:
let vector = vec![1, 2, 3, 4];
let mut slice = &vector[..];
read_something(&mut slice);
Note that this makes the slice mutable, meaning it can be modified to refer to different data (which read_something() makes use of). It doesn't grant the slice ability to mutate the immutable vector.
How do these two cases differ? Why does the first example work even though the vector is not declared as mutable either?
In the first case the vector is not mutable, but the unnamed temporary that holds the slice is. Your first case desugars to something like:
let vector = vec![1, 2, 3, 4]; // immutable Vec
let mut tmp = &vector[..]; // mutable slice referring to immutable Vec
read_something(&mut tmp);
// here `tmp` may be pointing to different content
// (e.g. a subset of the vector, or something static)
The vector doesn't need to be mutable because the Read::read() impl for &[u8] doesn't attempt to modify the contents of the slice, it only modifies the slice (conceptually a <pointer, length> tuple) itself. It can do that because Read is implemented for &[u8], so when <&[u8] as Read>::read() receives &mut self, its full type is &mut &[u8] - a mutable reference to some slice of immutable data.
What Read::read() for &[u8] does is replace the received slice with a smaller slice which encompasses the as-yet-unread portion of the slice. (This allows "the same" slice to be passed to read() to eventually exhaust all data.) Since the 8-byte buffer you read into is larger than the 4-byte slice that serves as reading source, the modified tmp slice will be empty after read_something() returns (playground).
I have a vector of numbers and use the windows(2) method to create an iterator that gives me neighbouring pairs. For example, the vector [1, 2, 3] is transformed into [1, 2], [2, 3]. I want to use the find method to find a slice that fulfills a specific condition:
fn step(g: u64) -> Option<(u64, u64)> {
let prime_list: Vec<u64> = vec![2, 3, 5, 7]; //For example
if prime_list.len() < 2 {
return None;
}
let res = prime_list.windows(2).find(|&&[a, b]| b - a == g)?;
//...
None
}
I get an error:
error[E0005]: refutable pattern in function argument: `&&[]` not covered
--> src/lib.rs:6:43
|
6 | let res = prime_list.windows(2).find(|&&[a, b]| b - a == g)?;
| ^^^^^^^^ pattern `&&[]` not covered
I don't know what that error means: the list cannot have less than two elements, for example. Maybe the closure parameter is wrong? I tried to vary it but that didn't change anything. a and b are being properly detected as u64 in my IDE too. What is going on here?
You, the programmer, know that each iterated value will have a length of 2, but how do you know that? You can only tell that from the prose documentation of the function:
Returns an iterator over all contiguous windows of length size. The windows overlap. If the slice is shorter than size, the iterator returns no values.
Nowhere does the compiler know this information. The implementation of Windows only states that the iterated value will be a slice:
impl<'a, T> Iterator for Windows<'a, T> {
type Item = &'a [T];
}
I'd convert the slice into an array reference, discarding any slices that were the wrong length (which you know cannot happen):
use std::convert::TryFrom;
fn step(g: u64) -> Option<(u64, u64)> {
let prime_list: Vec<u64> = vec![2, 3, 5, 7]; // For example
if prime_list.len() < 2 {
return None;
}
let res = prime_list
.windows(2)
.flat_map(<&[u64; 2]>::try_from)
.find(|&&[a, b]| b - a == g)?;
//...
None
}
See also:
How to convert a slice into an array reference?
How can I find a subsequence in a &[u8] slice?
How do I imply the type of the value when there are no type parameters or ascriptions?
Alternatively, you could use an iterator of integers and chunk it up.
See also:
Are there equivalents to slice::chunks/windows for iterators to loop over pairs, triplets etc?
At some point in the future, const generics might be stabilized and allow baking the array length into the function call and the return type.
See also:
Is it possible to control the size of an array using the type parameter of a generic?
I have an input vector which contains numbers. In an output vector, I need to get a sequence of partial products but in right-to-left order. The last element of the output must be equal to the last one in the input; the second-to-last element of the output must be a product of the last and second-to-last elements of input; and so on. For example, if the input vector is
let input = vec![2, 3, 4];
then I need the output to be [24, 12, 4].
My implementation takes an iterator over the input, reverses it, maps, reverses again and collects:
fn main() {
let input = vec![2, 3, 4];
let mut prod = 1;
let p: Vec<usize> = input
.iter()
.rev()
.map(|v| {
prod *= v;
prod
}).rev()
.collect();
println!("{:?}", p);
}
The result is [2, 6, 24], the same as if I delete both rev()s. The two rev()s do not solve the problem, they just "annihilate" each other.
Is this task solvable in "chain of calls" style, without using for?
This behavior is actually explicitly described in the documentation:
Notes about side effects
The map iterator implements DoubleEndedIterator, meaning that
you can also map backwards:
[…]
But if your closure has state, iterating backwards may act in a way you do
not expect. […]
A way to solve this would be by adding an intermediary collect to be sure that the second rev does not apply on the Map:
fn main() {
let input = vec![2, 3, 4];
let mut prod = 1;
let p: Vec<usize> = input
.iter()
.map(|v| {
prod *= v;
prod
}).rev()
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect();
println!("{:?}", p);
}
But that requires an extra allocation. Another way would be to collect, and then reverse:
fn main() {
let input = vec![2, 3, 4];
let mut prod = 1;
let mut p: Vec<usize> = input
.iter()
.rev()
.map(|v| {
prod *= v;
prod
}).collect();
p.reverse();
println!("{:?}", p);
}
Your prod variable is carrying state across from one item to the next, which is not what a mapping does. Mappings operate on each element independently, which makes them easily parallelized and easier to reason about. The result you're asking for is to be precise a right scan (a reversed case of a prefix sum), but I'm not sure there are convenient methods to collect from the right (probably the easiest mutable way would be using VecDeque::push_front). This led me to perform the operation in two passes for my first version:
fn main() {
let input: Vec<usize> = vec![2, 3, 4];
let initprod = 1;
let prev: Vec<usize> = input
.iter()
.rev()
.scan(initprod, |prod, &v| {
*prod *= v;
Some(*prod)
}).collect();
let p: Vec<usize> = prev.into_iter().rev().collect();
println!("{:?}", p);
}
Note that initprod is immutable; prod carries the state. Using into_iter also means prev is consumed. We could use vec.reverse as shown by mcarton, but then we need to have a mutable variable. Scans can be parallelized, but to a lesser degree than maps. See e.g. discussion on adding them to Rayon. One might also consider if a ExactSizeIterator should allow reverse collection into an ordinary vector, but the standard library scan method breaks the known size using Option (which by the next convention turns it into a take-while-scan).
Here's a fewer copy variant using a preallocated VecDeque to collect from the right. I used an extra scope to restrict the mutability. It also requires Rust 1.21 or later to use for_each. There's unnecessary overhead in tracking the number of items and ring buffer structure, but it's at least somewhat legible still.
use std::collections::VecDeque;
fn main() {
let input: Vec<usize> = vec![2,3,4];
let p = {
let mut pmut = VecDeque::with_capacity(input.len());
let initprod = 1;
input
.iter()
.rev()
.scan(initprod, |prod, &v| {
*prod *= v;
Some(*prod)
})
.for_each(|v| {
pmut.push_front(v)
});
pmut
};
println!("{:?}", p);
}
Incidentally, following the old adage about Lisp programmers knowing the value of everything and the cost of nothing, here's a Haskell version I don't really know how inefficient it is:
scanr1 (*) [2, 3, 4]
I'm just playing around with rust for the first time, implementing quicksort, and I'm stuck on references to dynamically sized arrays (I had no problem with fixed size arrays).
I would like to have an indefinitely sized array of integers to sort, which I gather I can create with something like:
let array = ~[1,2,3,4,3,2,1];
However, I am not sure how I can pass this by reference into a partition function.
partition ( a : &mut ~[uint], p: uint, i: uint) {
// partition a, in place
}
As soon as I try to reorder any elements in a, the compiler complains:
error: cannot assign to immutable vec content a[..]
You should use a mutable borrow of the vector rather than a mutable borrow of a pointer to a vector, so you should get rid of that ~ pointer in the type of your partition function. For example:
fn partition(_: &mut [uint], _: uint, _: uint) { }
fn main() {
let mut array = ~[1, 2, 3, 4, 3, 2, 1];
partition(array, 0, 0);
}
Notice that array is automatically passed as a mutable borrowed pointer.
If you use a Vec instead, then you need to explicitly create a slice:
fn partition(_: &mut [uint], _: uint, _: uint) { }
fn main() {
let mut array = vec!(1, 2, 3, 4, 3, 2, 1);
partition(array.as_mut_slice(), 0, 0);
}
Both code snippets should compile on the latest Rust (from tip).
With 0.10 the language is undergoing some changes to array types at the moment, so things are a bit messy. Vec<T> is Rust's intended dynamically sized array type.
let vec = vec!(1u,2,3,4,3,2,1);
partition ( a : &mut Vec<uint>, p: uint, i: uint) {
// partition a, in place
}
Note that indexing of a Vec via brackets is currently only possible by first calling .as_slice() or .as_mut_slice() on it since the respective traits are not yet implemented.