Ask coding questions

← Back to all posts
Borrow of moved value in Rust?
DynamicSquid (4630)

I'm getting this weird error: "Borrow of moved value in Rust"

I looked online but I can't find anything. Does it have to do with the fact that your transferring ownership or something?

Thanks

Answered by fuzzyastrocat (1513) [earned 5 cycles]
View Answer
Comments
hotnewtop
fuzzyastrocat (1513)

You've just hit rust's biggest annoyance factor: memory safety. See, in Rust, memory is super safe — like, you literally can't get a memory error at runtime. However, this means you get all your memory errors are compile-time, which saves you the pain of runtime debugging but can get super annoying for a newbie rustacean.

So, let's look at what's going on here. In this loop:

for ch in line.chars() {
        token.push(ch);
        if token == "s" {
            tokens.push(Token{ value: token });
            token.clear();
        }
    }

On the first iteration where token == "s", the variable token gets moved into the token struct you create (Token { value: token }). It's there now. It's been moved out of the variable "token" and into the Token struct you've just made. So on the next loop where token == "s", it tries to move it out of the token variable again. But oh no, we've already moved it out of the token variable, so there's nothing in there! To fix this, instead of moving the token into the Token struct we can make a copy of the token and put it in that struct. You can do this like so:

for ch in line.chars() {
        token.push(ch);
        if token == "s" {
            tokens.push(Token{ value: token.clone() });
            token.clear();
        }
    }

Note the .clone(). Now, this will only work if the thing we are cloning implements the clone method (which std::String does) — if not, add #[derive(Clone)] above the definition of the struct that you're cloning.

fuzzyastrocat (1513)

@Coder100 That's a reference. It will now reference token, and since token is mutable that means it won't have the desired behavior. (You'll have multiple references to the same thing instead of many distinct things)

DynamicSquid (4630)

@fuzzyastrocat and #[derive(Clone)] is similar to inheritance?

fuzzyastrocat (1513)

@DynamicSquid Eh, kinda. #[derive(Clone)] is automatic inheritance — it basically auto-defines the .clone method for you, instead of you having to manually implement it.

DynamicSquid (4630)

@fuzzyastrocat Oh I see. Is the same true for parameters as well? So if I do line: String will the value be moved into the function?

fuzzyastrocat (1513)

@DynamicSquid Yep. Unless you otherwise specify, things will get moved.

How do you otherwise specify? Well, I've shown you the clone method, which is when you need to make several copies of something (as with this case – you need to copy token since you'll be modifying it later). But what if you don't need a copy? In that case, you can use a reference. I won't explain it here in too much detail, but there's some good info on it on the rust site.

Basically, a reference is when you don't need to have a copy of something. For instance, suppose you want to write a function which returns 2 * the length of the string. You don't need a copy for that, so you can use a reference instead:

fn double_length(s: &String) -> usize { // s is a reference to a String
    2 * s.len()
}

And now, you call it by passing a reference:

double_length(&my_str);
DynamicSquid (4630)

@fuzzyastrocat Okay. So just to be clear, I still have to use .clone() even when passing by reference right? And I have to use &mut if I want to change that reference?

fuzzyastrocat (1513)

@DynamicSquid No, I updated my comment. The point of a reference is to avoid .clone(). But yes, if you want to change the referenced value you'll need &mut.

DynamicSquid (4630)

@fuzzyastrocat Oh, okay, I get it now, thanks!

fuzzyastrocat (1513)

@DynamicSquid Great! Ownership in Rust is kinda hard at first, but once you do enough Rust it'll come naturally.

DynamicSquid (4630)

Oh @fuzzyastrocat, do you mind if I ask you another question? Sorry if I'm bothering you too much...

fuzzyastrocat (1513)

@DynamicSquid No, ask me as many questions as you like!

DynamicSquid (4630)

@fuzzyastrocat Okay, so I'm trying to create a vector of vectors, and I have to fill it with values, but I'm not sure how. Here's the repl. I know I can just .push() the 1D vector into the 2D vector, but I need to use a for loop for that since I'm doing some other stuff with it.

But I got a weird error about borrowing as mutable and immutable. Not sure what that means or how I can fix it... Do I have to use .clone()?

fuzzyastrocat (1513)

@DynamicSquid Thanks for inviting me to the repl. I'll help there.

DynamicSquid (4630)

@fuzzyastrocat Hi! I have another question if you don't mind :)

How do you turn a splice into a vector? Because I have a Vec, and I'm trying to pass it into another function, but I only want part of that Vec to be passed through. So my first though was to turn that Vec into a splice, and turn that splice into a Vec... or is that not the best way?

fuzzyastrocat (1513)

@DynamicSquid Nope, it's fine :D

(It's "slice" btw). Easy! Just call .to_vec() on the slice.

fuzzyastrocat (1513)

@DynamicSquid Note that using this method requires all the Vec elements to have the Clone trait, ie you can call .clone() on them, because it's creating a new vec. Therefore, it's not the most efficient in some cases — I'd look at the difference between to_vec and into_vec on the rust site.

DynamicSquid (4630)

@fuzzyastrocat Hey, I have another question if that's okay :) So I'm making an AST, and I just realized now that with unary operators, and multiple levels of precedence, it's getting quite complex. Do you think you could help me out?

fuzzyastrocat (1513)

@DynamicSquid HOW DARE YOU ASK ME A QUESTION (no, it's fine :D)

Sure! Do you mean me helping you with the code or with the theory?

DynamicSquid (4630)

@fuzzyastrocat More of the theory part. Is it okay if I invite you to a repl?

Summit (27)

wait why is everyone learning rust
i should learn rust
but i need to learn node.js first

waaa whichh should i learn first

DynamicSquid (4630)

@Summit lol learn what you want first, so nodejs

HahaYes (1862)

Rust: Laughs in memory safety

DynamicSquid (4630)

@HahaYes Rust is so memory safe it's insane

DynamicSquid (4630)

@HahaYes it's basically a super extra safer safe version of C++

DynamicSquid (4630)

@HahaYes with the naming conventions of Python... which I find quite weird

HahaYes (1862)

@DynamicSquid ikr rust memory safe is like a garbage can that asks you whether or not to put the garbage in i dunno

RayhanADev (1949)

Hey @DynamicSquid do you not have hacker?

DynamicSquid (4630)

@RayhanADev yeah :( but it shouldn't be to much of a problem since I don't much coding here, and I don't need private repls

fuzzyastrocat (1513)

@DynamicSquid I've never had hacker. What does it give you again? I know private repls, but other than that I forget.

RayhanADev (1949)

@fuzzyastrocat private repls, more storage, faster speeds. That’s pretty much it I believe.

RayhanADev (1949)

@fuzzyastrocat I got Hacker for a year free and I also got my bot account @HelperFurret hacker too for flex xD.

Coder100 (17104)

typo? Do tokens.push lol

DynamicSquid (4630)

@Coder100 no it's supposed to be token. I'm appending a char to a string

Coder100 (17104)

ah oops, but it got borrowed onto line 16, try referencing it instead @DynamicSquid

Coder100 (17104)

something like tokens.push(Token{ value: &token }) i believe @DynamicSquid

fuzzyastrocat (1513)

@DynamicSquid Don't do what @Coder100 is saying, you'll now have several references to the same token which isn't what you want. (All your Token structs will have the same value by the end of the loop.)

Coder100 (17104)

actually im curious what it does imma test it out @fuzzyastrocat