Staying DRY in rust - reference

Sometimes I have to act on information that is expressed in a long sequence, like:
f1(f2(f3).f4(x,f5(y,z))).f6().f7()
(not necessarily that, just any long sequence you don't want to repeat). And I may need to reference that multiple times, with other code in-between. Like this:
fn myfunc(v: &T) -> X {
match v.func(func(v.func().func())).func() {
...
}
.. other stuff ..
match v.func(func(v.func().func())).func() {
...
}
}
The value is not movable, so I cannot assign it to a variable and then reference the variable twice like in other languages, so essentially I find myself writing the same sequence of function calls multiple times. I tried something like this
let x = &( ... )
and then using this
*x
but this didn't work. I suppose I could use a macro, but then it would be recomputed each time (... which isn't too bad as most of the function calls are just sugar for the compiler and type system), but that's the best I have solved this so far. Is there another way?

If the value is not Copy, then you either need to copy it, or pass by reference. E.g. suppose it was computing a value of type T. I suppose the problem you're currently meeting is
fn foo(x: T) { ... }
fn bar(x: T) { ... }
let your_thing = f1(f2(f3).f4(x,f5(y,z))).f6().f7();
foo(your_thing);
bar(your_thing); // error: use of moved value
The correct fix is changing the foo lines to
fn foo(x: &T) { ... }
foo(&your_thing);
or, the foo call to foo(your_thing.clone()) (if T is Clone). You can decide which one is appropriate by thinking about what sort of ownership foo needs of the T: if it needs full ownership (e.g. passing it to different tasks), you should take it by value foo(x: T); on the other hand, if it only needs a view on to the data (i.e. no ownership), then take a reference foo(x: &T).
See also "Moves vs Copy in Rust" for some background on moving and copying. It includes an explanation of why the &(...) + *x solution isn't work: can't move out from behind a reference (although, in this case it will never work, because moving out twice is illegal anyway).
The same reasoning applies for pattern matching: if you only need a reference, you can take a reference into the value of interest via ref. E.g. imagine you're computing an Option<T>.
let x = v.func(func(v.func().func())).func()
match x {
Some(ref y) => { /* y is a &T */ ... }
None => { ... }
}
// the last `match` can move `x`
match x {
Some(y) => { /* y is a T */ ... }
None => { ... }
}
If the first match does need ownership of some parts of x, you can either clone x itself, or only those parts you need after matching with ref.

Related

How can I qualify or hold to a higher precedence a method not provided by a trait?

I have an Add implementation that looks like this,
impl<T: Into<u64>> Add<T> for Sequence {
type Output = Self;
fn add(self, rhs: T) -> Self::Output {
let mut o = self.clone();
o.myadd(rhs.into()).unwrap();
o
}
}
The function myadd returns a Result; This actually works fine. The problem is in the real world the method is Sequence.add() implemented on Sequence that I want the Add to call. If I rename myadd to add like this,
o.add(rhs.into()).unwrap();
Then it no longer compiles I get instead "error[E0599]: no method named unwrap found for struct sequence::Sequence in the current scope" which tells me that the add it's finding is not returning a Result, it's returning a Sequence which is not what I want. How can I qualify the trait in the call to add?
I was able to target add that I supplied under impl Sequence {} with the following,
Sequence::add(r, rhs.into()).unwrap();
You can also use
Self::add(r, rhs.into()).unwrap();

How can I define a trait function that takes an argument by reference

I came across this issue while experimenting with different ways to solve this question.
I'm trying to define a trait which takes an argument by reference, and returns Self, like this:
struct X {}
trait CopyFrom {
fn copy_from(&x: X) -> Self;
}
The error I get is:
error[E0642]: patterns aren't allowed in functions without bodies
--> src/main.rs:5:18
|
5 | fn copy_from(&x: X) -> Self;
| ^^ pattern not allowed in function without body
If I take x by value it compiles fine (but that would consume the argument, which I don't want).
The Rust reference has this to say:
The kinds of patterns for parameters is limited to one of the
following:
IDENTIFIER
mut IDENTIFIER
_
& IDENTIFIER
&& IDENTIFIER
Beginning in the 2018 edition, function or method parameter patterns
are no longer optional. Also, all irrefutable patterns are allowed as
long as there is a body. Without a body, the limitations listed above
are still in effect.
I was not able to find anything else that would explain why I can't define a trait function that takes an argument by reference.
You're using the wrong syntax here — &x: X is a reference pattern that dereferences the argument of type X; in other words,
fn f(&x: X) {
// ...
}
is equivalent to
fn f(x: X) {
let &x = x;
}
which, in turn, means
fn f(x: X) {
let x = *x;
}
Instead, you want to make the parameter itself a reference:
fn f(x: &X) { // take argument by reference
// ...
}

Is it possible to map a function over a Vec without allocating a new Vec?

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.

Iterating through a Vec within a struct - cannot move out of borrowed content

I am writing a function for a struct which contains a Vec where I attempt to iterate through the Vec:
struct Object {
pub v: Vec<f32>,
}
impl Object {
pub fn sum(&self) -> f32 {
let mut sum = 0.0;
for e in self.v {
sum += e;
}
sum
}
}
However I get the following error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:8:18
|
8 | for e in self.v {
| ^^^^ cannot move out of borrowed content
My understanding is that since self is borrowed and that the for loop iteration is attempting to move the elements of v out into e.
From the error code, I read that a potential solution is to take ownership but I'm not quite certain how to do that.
I'm not trying to modify the vector or its elements. I just want to use the elements to run some computation.
The line: for e in self.v is essentially saying for e in (*self).v; you're attempting to iterate over the vector by move, invoking its IntoIterator trait. This would destroy the vector completely, moving all the numbers out of it forever, which is not only not what you want, but also not allowed in this context because you're only allowed to read it.
You actually want to iterate over it by reference. There are two ways to do this:
for e in &self.v {
// ...
}
This is essentially saying &((*self).v), since the . auto-dereferences you need to tell the compiler that you actually just want to borrow the vector.
or
for e in self.v.iter() {
// ...
}
This may look funny because iter takes an &self. Why? Well, the compiler also auto-references if you call a function on a value that takes a reference. This is essentially (&((*self).v)).iter(), but that would suck to write so the compiler helps out.
So why doesn't it auto-reference in the for loop? Well, for x in self.v is a valid statement, and that may be what you intended to write. It's usually more important for the compiler to tell you that what you want want is impossible than assume you wanted something else. With the auto (de-)referencing above, no such ambiguity exists.
The former solution is preferred, but the latter is necessary if you want to use an iterator adapter.
Speaking of which, your sum already exists: just write self.v.iter().sum().

Boxed value does not live long enough

I'm trying to implement a cons list in Rust as an exercise. I've managed to solve all of my compiler errors except this one:
Compiling list v0.0.1 (file:///home/nate/git/rust/list)
/home/nate/git/rust/list/src/main.rs:18:24: 18:60 error: borrowed value does not live long enough
/home/nate/git/rust/list/src/main.rs:18 List::End => list = &*(box List::Node(x, box List::End)),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/nate/git/rust/list/src/main.rs:16:34: 21:2 note: reference must be valid for the anonymous lifetime #1 defined on the block at 16:33...
/home/nate/git/rust/list/src/main.rs:16 fn add(mut list: &List, x: uint) {
/home/nate/git/rust/list/src/main.rs:17 match *list {
/home/nate/git/rust/list/src/main.rs:18 List::End => list = &*(box List::Node(x, box List::End)),
/home/nate/git/rust/list/src/main.rs:19 List::Node(_, ref next_node) => add(&**next_node, x),
/home/nate/git/rust/list/src/main.rs:20 }
/home/nate/git/rust/list/src/main.rs:21 }
/home/nate/git/rust/list/src/main.rs:18:16: 18:60 note: ...but borrowed value is only valid for the expression at 18:15
/home/nate/git/rust/list/src/main.rs:18 List::End => list = &*(box List::Node(x, box List::End)),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `list`.
To learn more, run the command again with --verbose.
And the code that I'm trying to compile:
enum List {
Node(uint, Box<List>),
End,
}
fn main() {
let mut list = new();
add(&*list, 10);
//add(list, 20);
//add(list, 30);
print(&*list);
}
fn add(mut list: &List, x: uint) {
match *list {
List::End => list = &*(box List::Node(x, box List::End)),
List::Node(_, ref next_node) => add(&**next_node, x),
}
}
fn new() -> Box<List> {
box List::End
}
So why don't the boxed values live long enough? Is it because I immediately dereference them? I tried it this way:
match *list {
List::End => {
let end = box List::Node(x, box List::End);
list = &*end;
}
List::Node(_, ref next_node) => add(&**next_node, x),
}
But I got exactly the same error. What am I missing?
I think you’re missing some key details of Rust; there are three things that I think we need to deal with:
How patterns work;
The distinction between immutable (&) and mutable (&mut) references;
How Rust’s ownership model works (because of your &*box attempts).
I’ll deal with the patterns part first; in fn add(mut list: &List, x: uint), there are two patterns being used, mut list and x. Other examples of patterns are the left hand side of let lhs = rhs; and the bit before the => on each branch of a match expression. How are these patterns applied to calls, effectively? It’s really like you’re doing this:
fn add(__arg_0: &List, __arg_1: uint) {
let mut list = __arg_0;
let x = __arg_1;
…
}
Perhaps that way of looking at things will make it clearer; the signature of a function does not take the patterns that the variables are bound to into account at all. Your function signature is actually in canonical form fn add(&List, uint). The mut list part just means that you are binding the &List value to a mutable name; that is, you can assign a new value to the list name, but it has no effect outside the function, it’s purely a matter of the binding of a variable to a location.
Now onto the second issue: learn the distinction between immutable references (type &T, value &x) and mutable references (type &mut T, value &x). These are so fundamental that I won’t go into much detail here—they’re documented sufficiently elsewhere and you should probably read those things. Suffice it to say: if you wish to mutate something, you need &mut, not &, so your add method needs to take &mut List.
The third issue, that of ownership: in Rust, each object is owned in precisely one location; there is no garbage collection or anything, and this uniqueness of ownership means that as soon as an object passes out of scope it is destroyed. In this case, the offending expression is &*(box List::Node(x, box List::End)). You have boxed a value, but you haven’t actually stored it anywhere: you have just tried to take a reference to the value contained inside it, but the box will be immediately dropped. What you actually want in this case is to modify the contents of the List; you want to write *list = List::Node(x, box List::End), meaning “store a List::Node value inside the contents of list” instead of list = &…, meaning “assign to the variable list a new reference”.
You’ve also gone a tad overboard with the boxing of values; I’d tend to say that new() should return a List, not a Box<List>, though the question is slightly open to debate. Anyway, here’s the add method that I end up with:
fn add(list: &mut List, x: uint) {
match *list {
List::End => *list = List::Node(x, box List::End),
List::Node(_, box ref mut next_node) => add(next_node, x),
}
}
The main bit you may have difficulty with there is the pattern box ref mut next_node. The box ref mut part reads “take the value out of its box, then create a mutable reference to that value”; hence, given a Box<List>, it produces a &mut List referring to the contents of that box. Remember that patterns are completely back to front compared with normal expressions.
Finally, I would strongly recommend using impls for all of this, putting all the methods on the List type:
enum List {
Node(uint, Box<List>),
End,
}
impl List {
fn new() -> List {
List::End
}
fn add(&mut self, x: uint) {
match *self {
List::End => *self = List::Node(x, box List::End),
List::Node(_, box ref mut next_node) => next_node.add(x),
}
}
}
fn main() {
let mut list = List::new();
list.add(10);
}
Your attempts to fix the other compiler errors have, unfortunately, led you to a dark place of inconsistency. First you need to make up your mind whether you want a Box<List> or a List as your handle for the head of a (sub-)list. Let's go with List because that is more flexible and generally the path of least resistance.
Then, you need to realize there is a difference between mut list: &List and list: &mut List. The first is a read-only reference which you can change to point at other read-only things. The second is a read-write reference which you can not change to point at other read-write things. There's also mut list: &mut List because these two capabilities are orthogonal.
In add, when you write list = ..., you are only affecting your local variable. It has no effect on the caller. You want to change the list node the caller sees! Since we said we wanted to deal with List, not boxes, we'll change the contents of the list nodes that exist (replacing the final End with a Node(..., box End)). That is, signature and code change as follows:
fn add(list: &mut List, x: uint) {
match *list {
List::End => *list = List::Node(x, box List::End),
List::Node(_, box ref mut next_node) => add(next_node, x),
}
}
Note that *list = is different from list =, in that we now change the contents of the list node in-place instead of making our local reference point at a different node.
For consistency and ergonomics (and a tiny bit of efficiency), you should probably change new to return a bare List, i.e.:
fn new() -> List {
List::End
}
This also saves you all the nasty reborrowing (&*) in the calls:
let list = new(); // type: List
add(&mut list, 10);
Finally, as for why the box did not live long enough: Well, you basically created a local/temporary box, took a reference to it, and then attempted to pass on the reference without keeping the box alive. A box without an owner is deallocated, so you need to give it an owner. In the fixed code above, the owner is the next field of the List::Node we create and write to the &mut List.

Resources