1

This code causes a error. It seems reasonable, because the ownership has moved:

fn main() {
    let mut arr = vec![1, 2];
    let mut arr2 = vec![2, 6];
    arr = arr2;
    arr2[1] = 2;
}
error[E0382]: borrow of moved value: `arr2`
 --> src/main.rs:5:5
  |
3 |     let mut arr2 = vec![2, 6];
  |         -------- move occurs because `arr2` has type `Vec<i32>`, which does not implement the `Copy` trait
4 |     arr = arr2;
  |           ---- value moved here
5 |     arr2[1] = 2;
  |     ^^^^ value borrowed here after move

This code won't cause an error:

fn main() {
    let mut arr = [1, 2];
    let mut arr2 = [2, 4];
    arr = arr2;
    arr2[1] = 2;
}

This will cause an error:

fn main() {
    let mut arr = ["1".to_string(), "2".to_string()];
    let mut arr2 = ["2".to_string(), "4".to_string()];
    arr = arr2;
    arr2[1] = "2".to_string();
}
error[E0382]: use of moved value: `arr2`
 --> src/main.rs:5:5
  |
3 |     let mut arr2 = ["2".to_string(), "4".to_string()];
  |         -------- move occurs because `arr2` has type `[String; 2]`, which does not implement the `Copy` trait
4 |     arr = arr2;
  |           ---- value moved here
5 |     arr2[1] = "2".to_string();
  |     ^^^^^^^ value used here after move

This works fine...

fn main() {
    let mut arr = ["1", "2"];
    let mut arr2 = ["2", "4"];
    arr = arr2;
    arr2[1] = "2";
}

I am completely confused.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Cyberlin
  • 195
  • 5
  • 3
    `Vec` does not implement `Copy`. Arrays of `T` implement `Copy` if `T: Copy`. `String` does not implement `Copy`, but integers and shared references do. Therefore your arrays of integers and `&str`s are being copied, but your `Vec`s and array of `String`s cannot be—and so a move is attempted (and fails) instead. – eggyal Jun 30 '21 at 09:28
  • 1
    The reason that `Vec` and `String` do not implement `Copy` is that they own heap allocations (which are not cheaply copyable). If you're *sure* that you want new heap allocations (which is a relatively expensive operation), you can `clone` them instead. – eggyal Jun 30 '21 at 09:39
  • 1
    [Why not upload images of code/errors when asking a question?](https://meta.stackoverflow.com/questions/285551/why-not-upload-images-of-code-errors-when-asking-a-question/285557#285557) – Jmb Jun 30 '21 at 12:04
  • @Jmb Thanks for remanding,I don't know that before ..sorry – Cyberlin Jun 30 '21 at 12:08
  • 1
    @Cyberlin: now that you know, could you update the post? – Sergio Tulentsev Jun 30 '21 at 12:37

3 Answers3

3

In Rust all types fall into one of two categories:

  • copy-semantic (if it implements the Copy-trait)
  • move-semantic (if it does not implement the Copy-trait)

These semantics are implicitly employed by Rust whenever you e.g. assign a value to a variable. You can't choose it at the assignment. Instead, it depends only on the type in question. Therefore, whether a in the example below is moved or copied, depends entirely on what T is:

let a: T = /* some value */;
let b = a; // move or copy?

Also notice, that generic types are rather a set of similar types, than a single type by themselves (i.e. it is not a concrete type). For instance, you can't tell whether [T;2] is Copy or not, since it is not a concrete type (would need to know T first). Thus, [&str;2] and [String;2] are two totally different concrete types, and consequently one can be Copy and the other not.

To further elaborate, a concrete type can only be Copy if all constituting types are Copy. For instance, arrays [T;2] might be Copy (if T is too), Vec may never be Copy (independent of T).

So in your examples, when it does not compile due to move-semantics, you either have a Vec that is not Copy or String that is not, and any combinations with them can not be Copy either. Only if you combine Copy-types (arrays, ints, &str) you get copy-semantics, and your examples compile.

Also, this not an issue about ownership, because if you have copy-semantics you can just generate new values (by coping them) wherever you need, which gives you (fresh) ownership of these new values.

Cryptjar
  • 1,079
  • 8
  • 13
1

Couple of things here. First of all you are not changing the ownership in the working examples. You are merely borrowing their values. The difference in your not working examples is that in them you are actually changing the ownership.

As @eggyal correctly pointed out String and Vec don't implement Copy and that's important because Copy is used automatically when assigning another variable to a new variable. and in your working examples you have i32 (default for numeric types) and &str(also known as a string slice) which both implement Copy.

Every string literal is initially a &str and not a String. The .to_string() method in your example converts a &str into a String. If you want more in-depth information about the differences between &str and String I suggest you either check this answer or read an article about it but what's most important in your case is that string slices point to a read-only portion of the memory making them effectively immutable and therefore safe for copying.

InsertKnowledge
  • 1,012
  • 1
  • 11
  • 17
1

The compiler nowadays is so good that it tells you the entire story. I compiled your code and got this wonderful error message:


   |
18 |     let mut a = vec![2, 4];
   |         ----- move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
19 |     let b = a;
   |             - value moved here
20 |     println!("{:?}", a);
   |                      ^ value borrowed here after move

Alex Deft
  • 2,531
  • 1
  • 19
  • 34