Im building a data structure containing nodes, and each node might point to another.
The pointers between the nodes are implemented using Rc, something like this:
struct Node {
ptr: Rc<Node>
}
I would like to be able to change the pointer 'ptr' of a node to point to another node, by cloning another existing Rc.
let a: Rc<Node> = ...;
let mut b: Node = ...;
let b.ptr = a.clone();
My problem is, the compiler think I am trying to set the value of the node, namely changing the underlying shared object of b.ptr, where I realy want to replace the pointer:
reduce the refcount of the old value of b.ptr, increase the refcount of a, and change b.ptr to point to a.
I managed to do it with Cell<Rc>, but I seems too vebose and unnecessary.
How can I do that?
My problem is, the compiler think I am trying to set the value of the node, namely changing the underlying shared object of b.ptr
That's rather unlikely given the code you posted, and with code which is incomplete, separately broken, and without the error message, it's difficult to diagnose. Even Shepmaster has yet to achieve psychic powers letting him know information not provided.
Fixing the obviously missing or incorrect I get something like:
use std::rc::Rc;
struct Node {
ptr: Option<Rc<Node>>,
}
fn main() {
let a = Rc::new(Node { ptr: None });
let b = Node { ptr: None };
b.ptr = a.clone().into();
}
and the error message is completely clear:
error[E0594]: cannot assign to `b.ptr`, as `b` is not declared as mutable
--> src/main.rs:8:5
|
7 | let b = Node { ptr: None };
| - help: consider changing this to be mutable: `mut b`
8 | b.ptr = a.clone().into();
| ^^^^^ cannot assign
this is fixed by simply declaring b as mutable as the compiler suggests[0]:
use std::rc::Rc;
struct Node {
ptr: Option<Rc<Node>>,
}
fn main() {
let a = Rc::new(Node { ptr: None });
let mut b = Node { ptr: None };
b.ptr = a.clone().into();
}
[0]: not that it's always right, far from it, but in this case its suggestion is fine.
Related
I have a Vec of structs and I want to get the ones from position x to y:
fn main() {
#[derive(Debug)]
struct A {
name: String,
}
let x = A { name: "X".to_string() };
let y = A { name: "Y".to_string() };
let z = A { name: "Z".to_string() };
let v = vec!(x,y,z);
println!("{:?}", v[0..1]);
}
Here's the Rust Playground link for it.
I'm getting the error:
error[E0277]: the size for values of type `[A]` cannot be known at compilation time
--> src/main.rs:13:5
|
13 | println!("{:?}", v[0..1]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
How can I make sure the size is known at compile time? I couldn't find any obvious answer, therefore I think I'm missing something fundamental.
Change
println!("{:?}", v[0..1]);
To
println!("{:?}", &v[0..1]);
Indexing a Vec with a Range returns a slice which is sized, but when you use [] on a variable the compiler automatically dereferences the returned value (it's just syntax sugar), which in this case makes the slice unsized, so you have to put a reference in front of it to make it sized again.
See also:
Rust doesn't have a size known at compile-time
What is the return type of the indexing operation?
I have the following:
enum SomeType {
VariantA(String),
VariantB(String, i32),
}
fn transform(x: SomeType) -> SomeType {
// very complicated transformation, reusing parts of x in order to produce result:
match x {
SomeType::VariantA(s) => SomeType::VariantB(s, 0),
SomeType::VariantB(s, i) => SomeType::VariantB(s, 2 * i),
}
}
fn main() {
let mut data = vec![
SomeType::VariantA("hello".to_string()),
SomeType::VariantA("bye".to_string()),
SomeType::VariantB("asdf".to_string(), 34),
];
}
I would now like to call transform on each element of data and store the resulting value back in data. I could do something like data.into_iter().map(transform).collect(), but this will allocate a new Vec. Is there a way to do this in-place, reusing the allocated memory of data? There once was Vec::map_in_place in Rust but it has been removed some time ago.
As a work-around, I've added a Dummy variant to SomeType and then do the following:
for x in &mut data {
let original = ::std::mem::replace(x, SomeType::Dummy);
*x = transform(original);
}
This does not feel right, and I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop. Is there a better way of doing this?
Your first problem is not map, it's transform.
transform takes ownership of its argument, while Vec has ownership of its arguments. Either one has to give, and poking a hole in the Vec would be a bad idea: what if transform panics?
The best fix, thus, is to change the signature of transform to:
fn transform(x: &mut SomeType) { ... }
then you can just do:
for x in &mut data { transform(x) }
Other solutions will be clunky, as they will need to deal with the fact that transform might panic.
No, it is not possible in general because the size of each element might change as the mapping is performed (fn transform(u8) -> u32).
Even when the sizes are the same, it's non-trivial.
In this case, you don't need to create a Dummy variant because creating an empty String is cheap; only 3 pointer-sized values and no heap allocation:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
let old = std::mem::replace(self, VariantA(String::new()));
// Note this line for the detailed explanation
*self = match old {
VariantA(s) => VariantB(s, 0),
VariantB(s, i) => VariantB(s, 2 * i),
};
}
}
for x in &mut data {
x.transform();
}
An alternate implementation that just replaces the String:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
*self = match self {
VariantA(s) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 0)
}
VariantB(s, i) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 2 * *i)
}
};
}
}
In general, yes, you have to create some dummy value to do this generically and with safe code. Many times, you can wrap your whole element in Option and call Option::take to achieve the same effect .
See also:
Change enum variant while moving the field to the new variant
Why is it so complicated?
See this proposed and now-closed RFC for lots of related discussion. My understanding of that RFC (and the complexities behind it) is that there's an time period where your value would have an undefined value, which is not safe. If a panic were to happen at that exact second, then when your value is dropped, you might trigger undefined behavior, a bad thing.
If your code were to panic at the commented line, then the value of self is a concrete, known value. If it were some unknown value, dropping that string would try to drop that unknown value, and we are back in C. This is the purpose of the Dummy value - to always have a known-good value stored.
You even hinted at this (emphasis mine):
I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop
That "should" is the problem. During a panic, that dummy value is visible.
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
Temporarily move out of borrowed content
How do I move out of a struct field that is an Option?
The now-removed implementation of Vec::map_in_place spans almost 175 lines of code, most of having to deal with unsafe code and reasoning why it is actually safe! Some crates have re-implemented this concept and attempted to make it safe; you can see an example in Sebastian Redl's answer.
You can write a map_in_place in terms of the take_mut or replace_with crates:
fn map_in_place<T, F>(v: &mut [T], f: F)
where
F: Fn(T) -> T,
{
for e in v {
take_mut::take(e, f);
}
}
However, if this panics in the supplied function, the program aborts completely; you cannot recover from the panic.
Alternatively, you could supply a placeholder element that sits in the empty spot while the inner function executes:
use std::mem;
fn map_in_place_with_placeholder<T, F>(v: &mut [T], f: F, mut placeholder: T)
where
F: Fn(T) -> T,
{
for e in v {
let mut tmp = mem::replace(e, placeholder);
tmp = f(tmp);
placeholder = mem::replace(e, tmp);
}
}
If this panics, the placeholder you supplied will sit in the panicked slot.
Finally, you could produce the placeholder on-demand; basically replace take_mut::take with take_mut::take_or_recover in the first version.
I'm trying to make a simple example involving a vector of structs to learn Rust. All examples of vectors in the Rust literature I've found only use vectors of integers.
I want to write a function aimed at filling a vector, allowing the possibility of the element to be inserted to be changed, I can't figure out what to do. I always got a compiler error[E0308]: mismatched types on
the push method, because elem is a reference to a Point. So
push() needs a Point structure because v is a vector of Point
but if I want to modify elem, I need to pass a (mutable?) reference
What is the right thing to do?
// structure used everywhere in Rust examples
#[derive(Debug)]
struct Point {
x: i16,
y: i16
}
fn add_element(v: &mut Vec<Point>, elem: &Point) {
// modify element
elem.x = 0;
// add element
v.push(elem);
}
// this example is meant to study a vector of structs
fn main() {
// declare 2 points. By default, live on the stack
let origin = Point {x:0, y:0};
println!("origin address\t: {:p}", &origin);
let mut p1 = Point {x:1, y:1};
println!("p1 address\t: {:p}", &p1);
// declare a new vector of structs. Allocation is made in the heap
// declare mutable because we'll add elements to vector
let mut v: Vec<Point> = Vec::new();
// add points
add_element(&mut v, &origin);
add_element(&mut v, &p1);
// change p1
p1.x = 2;
p1.y = 2;
}
Let's read the error messages together:
error[E0308]: mismatched types
--> src/main.rs:10:12
|
10 | v.push(elem);
| ^^^^ expected struct `Point`, found &Point
|
= note: expected type `Point`
= note: found type `&Point`
The code is attempting to store a reference to a Point in a Vec that is declared to hold entire Points. Since Rust is a statically- and strongly- typed language, the compiler tells you that you cannot do that. The fix is to accept a Point by value:
fn add_element(v: &mut Vec<Point>, elem: Point)
This leads to the next error:
error: cannot assign to immutable field `elem.x`
--> src/main.rs:9:5
|
9 | elem.x = 0;
| ^^^^^^^^^^
You cannot change members of elem because it is not marked as mutable. Mutability of a value is a property of the binding, so let's do that:
fn add_element(v: &mut Vec<Point>, mut elem: Point)
Then change the calling of that function to adapt:
fn main() {
let origin = Point { x: 0, y: 0 };
let p1 = Point { x: 1, y: 1 };
let mut v = Vec::new();
add_element(&mut v, origin);
add_element(&mut v, p1);
}
Note that neither origin nor p1 need to be mutable because this function doesn't modify either while it owns it. It transfers ownership to add_element, which chooses to make it mutable.
but if I want to modify elem, I need to pass a (mutable?) reference
As you can see, you can simply make the elem parameter mutable when transferring the entire value to the function. Since the function owns that value, it has full control over it, including choosing to make it mutable.
What I am trying to do:
enum Test {
Value1,
Value2,
Value3
}
fn main() {
let mut test_vec: Vec<Test> = Vec::new();
test_vec.push(Test::Value2);
if let Some(last) = test_vec.last() {
test_vec.push(*last);
}
//Wanted output: vector with [Test::Value2, Test::Value2]
}
I understand that when I call last(), it will return Option<&Test>
So it will borrow the test_vec till the end of the if-let block.
I tried the following without success:
if let Some(last) = test_vec.last().map(|v| v.clone()) {
test_vec.push(*last);
}
//and
let last = test_vec.last().unwrap().clone();
test_vec.push(*last);
When trying to figure out why the borrow checker complains it can be useful to identify the types involved.
If you type out:
let _: () = test_vec.last().map(|v| v.clone());
you get an error complaining that () and core::option::Option<&Test> are not the same type.
What's going on? Very simply put, if you clone an &Test you get an &Test, thus calling .map(|v| v.clone()) on a Option<&Test> gives an Option<&Test>. Obviously, it still borrows.
The same problem occurs with your next attempt, if you type out:
let _: () = test_vec.last().unwrap().clone();
you get an error complaining that () and &Test are not the same type.
By calling unwrap on an Option<&Test> you get an &Test which is then cloned into an &Test.
So, the problem is a lack of dereferencing. You need to dereference earlier, to avoid borrowing test_vec in Some(last):
if let Some(last) = test_vec.last().map(|v| (*v).clone()) {
test_vec.push(last);
}
of course, this does not work because Test does not implement clone. Once that is fixed (by #[derive(Clone)]), it compiles.
Since cloning from references is such a common need, there is a dedicated method on Option (and Iterator) called cloned:
if let Some(last) = test_vec.last().cloned() {
test_vec.push(last);
}
To solve the borrow problem you can call Option::cloned, that produces a Option<T> from a Option<&T>. To do this, Test must implement Clone. You can implement Clone for Test using derive:
// To allow assert_eq, we also derive Debug and PartialEq
#[derive(Debug, PartialEq, Clone)]
enum Test {
Value1,
Value2,
Value3
}
fn main() {
let mut test_vec = Vec::new();
test_vec.push(Test::Value2);
if let Some(last) = test_vec.last().cloned() {
test_vec.push(last);
}
assert_eq!(vec![Test::Value2, Test::Value2], test_vec);
}
I have a program that more or less looks like this
struct Test<T> {
vec: Vec<T>
}
impl<T> Test<T> {
fn get_first(&self) -> &T {
&self.vec[0]
}
fn do_something_with_x(&self, x: T) {
// Irrelevant
}
}
fn main() {
let t = Test { vec: vec![1i32, 2, 3] };
let x = t.get_first();
t.do_something_with_x(*x);
}
Basically, we call a method on the struct Test that borrows some value. Then we call another method on the same struct, passing the previously obtained value.
This example works perfectly fine. Now, when we make the content of main generic, it doesn't work anymore.
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(*x);
}
Then I get the following error:
error: cannot move out of borrowed content
src/main.rs:14 let raw_x = *x;
I'm not completely sure why this is happening. Can someone explain to me why Test<i32> isn't borrowed when calling get_first while Test<T> is?
The short answer is that i32 implements the Copy trait, but T does not. If you use fn generic_main<T: Copy>(t: Test<T>), then your immediate problem is fixed.
The longer answer is that Copy is a special trait which means values can be copied by simply copying bits. Types like i32 implement Copy. Types like String do not implement Copy because, for example, it requires a heap allocation. If you copied a String just by copying bits, you'd end up with two String values pointing to the same chunk of memory. That would not be good (it's unsafe!).
Therefore, giving your T a Copy bound is quite restrictive. A less restrictive bound would be T: Clone. The Clone trait is similar to Copy (in that it copies values), but it's usually done by more than just "copying bits." For example, the String type will implement Clone by creating a new heap allocation for the underlying memory.
This requires you to change how your generic_main is written:
fn generic_main<T: Clone>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x.clone());
}
Alternatively, if you don't want to have either the Clone or Copy bounds, then you could change your do_something_with_x method to take a reference to T rather than an owned T:
impl<T> Test<T> {
// other methods elided
fn do_something_with_x(&self, x: &T) {
// Irrelevant
}
}
And your generic_main stays mostly the same, except you don't dereference x:
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x);
}
You can read more about Copy in the docs. There are some nice examples, including how to implement Copy for your own types.