1

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?

Ant Manelope
  • 531
  • 1
  • 6
  • 15

1 Answers1

1

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.

Community
  • 1
  • 1
huon
  • 94,605
  • 21
  • 231
  • 225
  • I embarrassingly don't have a concrete example as I moved past it in the code. But I recall it being like this: `fn myfunc(var: &T) -> X { match var.something().somethingelse(blah) { } .. more code ... match var.something().somethingelse(blah) { } }` – Ant Manelope Jul 02 '14 at 20:40
  • The error showed up on the 'let x=' part, being that I can't move out of a reference something or other. But maybe it wouldn't have if my matches used 'ref' as you say. I'll accept this and come back here if I run into it again. – Ant Manelope Jul 02 '14 at 21:12