How would I write the function below in Rust? Is there a way to write replace() safely or is the operation inherently unsafe? list does not have to be an array, a vector would work as well. It's the replacement operation that I'm interested in.
void replace(int *list[], int a, int b) {
*list[a] = *list[b];
}
I would like the following behavior:
int a = 1;
int b = 2;
int *list[] = { &a, &a, &b, &b };
*list[0] = 3; // list has pointers to values: [3, 3, 2, 2]
replace(list, 2, 0); // list has pointers to values: [3, 3, 3, 3]
*list[0] = 4; // list has pointers to values: [4, 4, 4, 4]
Answer for modified question
Rust does not allow you to have multiple mutable references (aliasing) to the same item. This means you'd never be able to run the equivalent of your third line:
fn main() {
let mut a = 1;
let vals = &[&mut a, &mut a];
}
This fails with:
cannot borrow `a` as mutable more than once at a time
What about using Rc and RefCell?
Rc doesn't let us mutate the value:
A reference-counted pointer type over an immutable value.
(Emphasis mine)
RefCell::borrow_mut won't allow multiple concurrent borrows:
Panics if the value is currently borrowed.
Answer for original question
It's basically the same. I picked a u8 cause it's easier to type. :-)
fn replace(v: &mut [&mut u8], a: usize, b: usize) {
*v[a] = *v[b]
}
fn main() {
let mut vals = vec![1,2,3,4];
{
let mut val_refs: Vec<&mut u8> = vals.iter_mut().collect();
replace(&mut val_refs, 0, 3);
}
println!("{:?}", vals);
}
(playpen link)
Rust does do boundary-checking, so if you call with an index bigger than the slice, the program will panic and you don't get memory corruption.
Related
Is there any straightforward way to insert or replace multiple elements from &[T] and/or Vec<T> in the middle or at the beginning of a Vec in linear time?
I could only find std::vec::Vec::insert, but that's only for inserting a single element in O(n) time, so I obviously cannot call that in a loop.
I could do a split_off at that index, extend the new elements into the left half of the split, and then extend the second half into the first, but is there a better way?
As of Rust 1.21.0, Vec::splice is available and allows inserting at any point, including fully prepending:
let mut vec = vec![1, 5];
let slice = &[2, 3, 4];
vec.splice(1..1, slice.iter().cloned());
println!("{:?}", vec); // [1, 2, 3, 4, 5]
The docs state:
Note 4: This is optimal if:
The tail (elements in the vector after range) is empty
or replace_with yields fewer elements than range’s length
or the lower bound of its size_hint() is exact.
In this case, the lower bound of the slice's iterator should be exact, so it should perform one memory move.
splice is a bit more powerful in that it allows you to remove a range of values (the first argument), insert new values (the second argument), and optionally get the old values (the result of the call).
Replacing a set of items
let mut vec = vec![0, 1, 5];
let slice = &[2, 3, 4];
vec.splice(..2, slice.iter().cloned());
println!("{:?}", vec); // [2, 3, 4, 5]
Getting the previous values
let mut vec = vec![0, 1, 2, 3, 4];
let slice = &[9, 8, 7];
let old: Vec<_> = vec.splice(3.., slice.iter().cloned()).collect();
println!("{:?}", vec); // [0, 1, 2, 9, 8, 7]
println!("{:?}", old); // [3, 4]
Okay, there is no appropriate method in Vec interface (as I can see). But we can always implement the same thing ourselves.
memmove
When T is Copy, probably the most obvious way is to move the memory, like this:
fn push_all_at<T>(v: &mut Vec<T>, offset: usize, s: &[T]) where T: Copy {
match (v.len(), s.len()) {
(_, 0) => (),
(current_len, _) => {
v.reserve_exact(s.len());
unsafe {
v.set_len(current_len + s.len());
let to_move = current_len - offset;
let src = v.as_mut_ptr().offset(offset as isize);
if to_move > 0 {
let dst = src.offset(s.len() as isize);
std::ptr::copy_memory(dst, src, to_move);
}
std::ptr::copy_nonoverlapping_memory(src, s.as_ptr(), s.len());
}
},
}
}
shuffle
If T is not copy, but it implements Clone, we can append given slice to the end of the Vec, and move it to the required position using swaps in linear time:
fn push_all_at<T>(v: &mut Vec<T>, mut offset: usize, s: &[T]) where T: Clone + Default {
match (v.len(), s.len()) {
(_, 0) => (),
(0, _) => { v.push_all(s); },
(_, _) => {
assert!(offset <= v.len());
let pad = s.len() - ((v.len() - offset) % s.len());
v.extend(repeat(Default::default()).take(pad));
v.push_all(s);
let total = v.len();
while total - offset >= s.len() {
for i in 0 .. s.len() { v.swap(offset + i, total - s.len() + i); }
offset += s.len();
}
v.truncate(total - pad);
},
}
}
iterators concat
Maybe the best choice will be to not modify Vec at all. For example, if you are going to access the result via iterator, we can just build iterators chain from our chunks:
let v: &[usize] = &[0, 1, 2];
let s: &[usize] = &[3, 4, 5, 6];
let offset = 2;
let chain = v.iter().take(offset).chain(s.iter()).chain(v.iter().skip(offset));
let result: Vec<_> = chain.collect();
println!("Result: {:?}", result);
I was trying to prepend to a vector in rust and found this closed question that was linked here, (despite this question being both prepend and insert AND efficiency. I think my answer would be better as an answer for that other, more precises question because I can't attest to the efficiency), but the following code helped me prepend, (and the opposite.) [I'm sure that the other two answers are more efficient, but the way that I learn, I like having answers that can be cut-n-pasted with examples that demonstrate an application of the answer.]
pub trait Unshift<T> { fn unshift(&mut self, s: &[T]) -> (); }
pub trait UnshiftVec<T> { fn unshift_vec(&mut self, s: Vec<T>) -> (); }
pub trait UnshiftMemoryHog<T> { fn unshift_memory_hog(&mut self, s: Vec<T>) -> (); }
pub trait Shift<T> { fn shift(&mut self) -> (); }
pub trait ShiftN<T> { fn shift_n(&mut self, s: usize) -> (); }
impl<T: std::clone::Clone> ShiftN<T> for Vec<T> {
fn shift_n(&mut self, s: usize) -> ()
// where
// T: std::clone::Clone,
{
self.drain(0..s);
}
}
impl<T: std::clone::Clone> Shift<T> for Vec<T> {
fn shift(&mut self) -> ()
// where
// T: std::clone::Clone,
{
self.drain(0..1);
}
}
impl<T: std::clone::Clone> Unshift<T> for Vec<T> {
fn unshift(&mut self, s: &[T]) -> ()
// where
// T: std::clone::Clone,
{
self.splice(0..0, s.to_vec());
}
}
impl<T: std::clone::Clone> UnshiftVec<T> for Vec<T> {
fn unshift_vec(&mut self, s: Vec<T>) -> ()
where
T: std::clone::Clone,
{
self.splice(0..0, s);
}
}
impl<T: std::clone::Clone> UnshiftMemoryHog<T> for Vec<T> {
fn unshift_memory_hog(&mut self, s: Vec<T>) -> ()
where
T: std::clone::Clone,
{
let mut tmp: Vec<_> = s.to_owned();
//let mut tmp: Vec<_> = s.clone(); // this also works for some data types
/*
let local_s: Vec<_> = self.clone(); // explicit clone()
tmp.extend(local_s); // to vec is possible
*/
tmp.extend(self.clone());
*self = tmp;
//*self = (*tmp).to_vec(); // Just because it compiles, doesn't make it right.
}
}
// this works for: v = unshift(v, &vec![8]);
// (If you don't want to impl Unshift for Vec<T>)
#[allow(dead_code)]
fn unshift_fn<T>(v: Vec<T>, s: &[T]) -> Vec<T>
where
T: Clone,
{
// create a mutable vec and fill it
// with a clone of the array that we want
// at the start of the vec.
let mut tmp: Vec<_> = s.to_owned();
// then we add the existing vector to the end
// of the temporary vector.
tmp.extend(v);
// return the tmp vec that is identitcal
// to unshift-ing the original vec.
tmp
}
/*
N.B. It is sometimes (often?) more memory efficient to reverse
the vector and use push/pop, rather than splice/drain;
Especially if you create your vectors in "stack order" to begin with.
*/
fn main() {
let mut v: Vec<usize> = vec![1, 2, 3];
println!("Before push:\t {:?}", v);
v.push(0);
println!("After push:\t {:?}", v);
v.pop();
println!("popped:\t\t {:?}", v);
v.drain(0..1);
println!("drain(0..1)\t {:?}", v);
/*
// We could use a function
let c = v.clone();
v = unshift_fn(c, &vec![0]);
*/
v.splice(0..0, vec![0]);
println!("splice(0..0, vec![0]) {:?}", v);
v.shift_n(1);
println!("shift\t\t {:?}", v);
v.unshift_memory_hog(vec![8, 16, 31, 1]);
println!("MEMORY guzzler unshift {:?}", v);
//v.drain(0..3);
v.drain(0..=2);
println!("back to the start: {:?}", v);
v.unshift_vec(vec![0]);
println!("zerothed with unshift: {:?}", v);
let mut w = vec![4, 5, 6];
/*
let prepend_this = &[1, 2, 3];
w.unshift_vec(prepend_this.to_vec());
*/
w.unshift(&[1, 2, 3]);
assert_eq!(&w, &[1, 2, 3, 4, 5, 6]);
println!("{:?} == {:?}", &w, &[1, 2, 3, 4, 5, 6]);
}
I've got code very similar to the following (my filter function is more complex though):
struct MyStruct {
a: i32,
b: i32,
count: i32,
}
impl MyStruct {
fn filter(&self) -> bool {
return self.a > self.b + self.count;
}
}
struct ContainerStruct<'a> {
x: i32,
v: Vec<&'a MyStruct>,
}
fn main() {
let mut list_of_items = vec![
MyStruct {
a: 1,
b: 2,
count: 0,
},
MyStruct {
a: 2,
b: 1,
count: 0,
},
MyStruct {
a: 5,
b: 2,
count: 0,
},
];
let mut count = 0;
let mut list_of_containers: Vec<ContainerStruct> = Vec::new();
while count < 10 {
let mut c = ContainerStruct {
x: 1,
v: Vec::new(),
};
for i in list_of_items.iter_mut() {
i.count = count;
if i.filter() {
c.v.push(i);
}
}
count += 1;
list_of_containers.push(c)
}
}
Which does not compile, due to the following error:
error[E0499]: cannot borrow `list_of_items` as mutable more than once at a time
--> src/main.rs:43:18
|
43 | for i in list_of_items.iter_mut() {
| ^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
I know this is a borrow-checking issue, and I can see the potential problems with references etc. What I don't know is the correct pattern to use to achieve what I'm looking for, which is essentially a vector of structs, where each struct contains a subset of an array of structs.
I need to be able to mutate the structs, so I'm forced into using iter_mut().
However that moves the vector into that scope which then gets released next time I go through the external while loop.
Is there any way to force the vector to live long enough to complete the outer loop? I thought about copying the structs but I don't want to do that. I only need references to each one and copying would introduce an unacceptable overhead due to the size of the vector in question.
This compiles:
use std::cell::Cell;
struct MyStruct {
a: i32,
b: i32,
count: Cell<i32>,
}
impl MyStruct {
fn filter(&self) -> bool {
return self.a > self.b + self.count.get();
}
}
struct ContainerStruct<'a> {
x: i32,
v: Vec<&'a MyStruct>,
}
fn main() {
let mut list_of_items = vec![
MyStruct {
a: 1,
b: 2,
count: Cell::new(0),
},
MyStruct {
a: 2,
b: 1,
count: Cell::new(0),
},
MyStruct {
a: 5,
b: 2,
count: Cell::new(0),
},
];
let mut count = 0;
let mut list_of_containers: Vec<ContainerStruct> = Vec::new();
while count < 10 {
let mut c = ContainerStruct {
x: 1,
v: Vec::new(),
};
for i in list_of_items.iter() {
i.count.set(count);
if i.filter() {
c.v.push(i);
}
}
count += 1;
list_of_containers.push(c)
}
}
If I have a struct:
pub struct Test {
val1: u8,
val2: u8,
}
and I make a vec! of these like:
let a = Test{val1: 1, val2: 1};
let b = Test{val1: 1, val2: 2};
let c = Test{val1: 1, val2: 2};
let my_vec = vec![a, b];
How can I tell if my_vec contains a struct with the same values as c?
Vec has a method, contains, for checking if it contains a particular value. The method requires that the elements implement PartialEq, which you can automatically derive like this:
#[derive(PartialEq)]
pub struct Test {
val1: u8,
val2: u8,
}
So now you can do:
assert!(my_vec.contains(&c));
If your collection gets large, this will be quite inefficient, since it will have to compare against every element until it finds one that matches. A HashSet would be more efficient, but comes with its own requirement that you need to implement Eq and Hash too. Luckily, those can usually be derived in the same way.
You need to impl PartialEq and the eq method as stated in https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
pub struct Test {
val1: u8,
val2: u8,
}
impl PartialEq for Test {
fn eq(&self, other: &Test) -> bool {
self.val1 == other.val1 && self.val2 == other.val2
}
}
fn main() {
let a = Test{val1: 1, val2: 1};
let b = Test{val1: 1, val2: 2};
let c = Test{val1: 1, val2: 2};
let my_vec = vec!(a, b);
println!("{}", my_vec.contains(&c));
}
I have the following code:
fn hailSeq(number: i32) -> Vec<i32> {
let mut vec = Vec::new();
vec.push(number);
if number == 1 {
vec.push(1);
return vec;
}
if number % 2 == 0 {
let num = number / 2;
vec.push(num);
hailSeq(num);
} else {
let num = 3 * number + 1;
vec.push(num);
hailSeq(num);
}
return vec;
}
It calculates the Hailstone sequence and stops at 1. The output should look like this for hailSeq(11):
[11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
However, my output looks like this:
[11, 34]
I am not really sure why this is occurring. Perhaps there is a limit on recursion in Rust that I don't know about, but I'm sure there's probably just an error in my code.
Your problem is not Rust-specific, but a more general problem.
On every call of hailSeq you create a new Vec every time, so that only the first vec (from the first call) would be used and returned, hence the [11, 34] (11 from the third line, 34 from the tenth line).
To fix this you have two options, I will provide one here.
The first one would be to extend the current vec with the returned vec, e.g. myvec.extend_from_slice(&returned_vec).
The second solution involves creating a vec on startup and passing the same instance to every call of the function.
fn hail_seq(number: i32) -> Vec<i32> {
fn inner(number: i32, vec: &mut Vec<i32>) {
vec.push(number);
if number == 1 {
return;
}
if number % 2 == 0 {
let num = number / 2;
inner(num, vec);
} else {
let num = 3 * number + 1;
inner(num, vec);
}
}
let mut v = vec![];
inner(number, &mut v);
v
}
fn main() {
println!("{:?}", hail_seq(11));
}
(playground)
As a side-note: If you know that a number can't be negative, use a u32 instead because you will find errors at compile time instead of runtime.
I can not find within the documentation of Vec<T> how to retrieve a slice from a specified range.
Is there something like this in the standard library:
let a = vec![1, 2, 3, 4];
let suba = a.subvector(0, 2); // Contains [1, 2];
The documentation for Vec covers this in the section titled "slicing".
You can create a slice of a Vec or array by indexing it with a Range (or RangeInclusive, RangeFrom, RangeTo, RangeToInclusive, or RangeFull), for example:
fn main() {
let a = vec![1, 2, 3, 4, 5];
// With a start and an end
println!("{:?}", &a[1..4]);
// With a start and an end, inclusive
println!("{:?}", &a[1..=3]);
// With just a start
println!("{:?}", &a[2..]);
// With just an end
println!("{:?}", &a[..3]);
// With just an end, inclusive
println!("{:?}", &a[..=2]);
// All elements
println!("{:?}", &a[..]);
}
If you wish to convert the entire Vec to a slice, you can use deref coercion:
fn main() {
let a = vec![1, 2, 3, 4, 5];
let b: &[i32] = &a;
println!("{:?}", b);
}
This coercion is automatically applied when calling a function:
fn print_it(b: &[i32]) {
println!("{:?}", b);
}
fn main() {
let a = vec![1, 2, 3, 4, 5];
print_it(&a);
}
You can also call Vec::as_slice, but it's a bit less common:
fn main() {
let a = vec![1, 2, 3, 4, 5];
let b = a.as_slice();
println!("{:?}", b);
}
See also:
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?