0

My code:

enum MyEnum1 {
  //....
}

struct Struct1 { 
  field1: MyEnum1,
  field2: String
}

fn fn1(a: Struct1, b: String, c: String) -> String {
  let let1 = fn2(a.field1);
  let let2 = fn3(let1, b, c);
  format!("{} something 123 {}", let1, let2)
}


fn fn2(a: MyEnum1) -> String {
  //....   
}

fn fn3(a: MyEnum1, b: Struct1) -> String {
  //....   
}


error: use of moved value: `a.field1`
error: use of moved value: `let1`

How can I fix them? Should I add & to the parameters of 'fn2andfn3? Ormut`? I can't understand the idea of how to fix these kind of errors.

  • 1
    your code produces different errors than you describe, please provide a working example – oli_obk Jun 22 '15 at 06:08
  • 1
    Your code is inconsistent. `fn3` declaration does not agree with how it is invoked. This code would give you type errors, not ownership ones. Please make your code [a compilable example](http://stackoverflow.com/help/mcve). – Vladimir Matveev Jun 22 '15 at 06:09

1 Answers1

4

These errors come from the most important concept in Rust - ownership. You should read the official book, especially the chapter on ownership - this would help you understand "how tho fix this kind of errors".

In short, specifically in your code, the problem is that String is a non-copyable type, that is, String values are not copied when passed to functions or assigned to local variables, they are moved. This means that wherever they were before, they are not accessible from there anymore.

Let's look at your function:

enum MyEnum1 {
  //....
}

struct Struct1 { 
  field1: MyEnum1,
  field2: String
}

fn fn1(a: Struct1, b: String, c: String) -> String {
  let let1 = fn2(a.field1);
  let let2 = fn3(let1, b, c);
  format!("{} something 123 {}", let1, let2)
}

fn fn2(a: MyEnum1) -> String {
  //....   
}

All types here are not automatically copyable (they don't implement Copy trait). String is not copyable because it is a heap-allocated string and copying would need a fresh allocation (an expensive operation which better be not implicit), MyEnum1 is not copyable because it does not implement Copy (with #[deriving(Copy, Clone)], for example; and it is unclear if it can be made copyable because you didn't provide its variants), and Struct1 is not copyable because it contains non-copyable types.

In fn1 you invoke fn2, passing it field1 and getting a String back. Then you immediately passes this String to fn3. Because String is not copyable, whatever is stored in let1 is moved into the called function, making let1 inaccessible. This is what "use of moved value" error is about. (The code you provided can't cause "use of moved value: a.field1" error, so it probably came from the parts you omitted, but the basic idea is absolutely the same)

There are several ways to fix these errors, but the most natural and common one is indeed to use borrowed references. In general if you only want to read some non-copyable value in a function you should pass it there by reference:

fn use_myenum(e: &MyEnum1)

For strings and arrays, however, the better way would be to pass slices:

fn use_str(s: &str) { ... }

let s: String = ...;
use_str(&s);  // here &String is automatically converted to &str

You can find more on slices in the book, here.

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • Thanks, that's what I need. One thing: how do I derefence `e` in `fn use_myenum(e: &MyEnum1)` - convert from a pointer to a "normal" MyEnum1? –  Jun 22 '15 at 07:28
  • Because when I'm trying to use `*e` I get "error: cannot move out of borrowed content" –  Jun 22 '15 at 07:33
  • 1
    even if this is the answer you were looking for, it would still be great if you updated your question to include a [MCVE](http://stackoverflow.com/help/mcve) – oli_obk Jun 22 '15 at 08:02
  • @jawanam, you can't just write `*e` and get the value of the enum because it is not copyable. You can match on the enum variant, it can be done if you don't move any values out of the variant: `match *e { MyEnum1::Variant1 => { ... } MyEnum1::Variant2(ref x, _) => { ... }`. – Vladimir Matveev Jun 22 '15 at 19:23
  • @jawanam, or, if you can make the enum copyable (with `#[derive(Copy, Clone)]`, for example), then writing `*e` will just work. – Vladimir Matveev Jun 22 '15 at 19:23