Skip to content

Visualizing Ownership and Moves

Daniel Cortes edited this page Jul 28, 2024 · 15 revisions

At the top is the simplified version and at the bottom is the full version of these rules.

The owner can be an argument, a struct, a vector or any data structure that can contain a value, can be an owner.

Whenever we take a value out of one owner and pass it to another variable or assign the value to any kind of data structure that will move the value from the old owner.

Lets write out some code snippets and a corresponding diagram to visualize a lot of these cases.

The 'account' binding is the owner of the 'Account' value

THen we call print_account(account); and pass in the account binding and so we take that value and move it to the 'print_account' function #1 and now it shows up there as the account argument.

Back inside the main() function, the next line of code is to call print_account(account); again and we are going to again reference the account binding. And so we say I want to use whatever value the 'account' binding is owning, but there is NO VALUE! there.

We can have owners that are function arguments, in addition to other kinds of data structures. Lets look at the case where the owner is a data structure right now.

This time its a bit more confusing and more complicated, because we have a value that is going to be the owner of another value. So lets break this down and think about what is happening behind the scenes.

We're making a brand new account and assign that value to the 'account' binding. THen on the next line of code we create a new vector and inside that vector we take ownership of the account value and so we move the Account Value and moving it into the vector and so now we take that entire value and assign it to list_of_accounts. So the vector of account value is being moved it to the list_of_accounts binding and then when we try to list the accounts its a reference to 'account' binding and there is NO VALUE there.

So on the first line of code we make a new value with Bank::new() and this is a struct and a field on a struct can own values. We also intialized a brand new vector of accounts, so you can imagine that on the first line of code we end up with a bank value that has an accounts field that is the owner of this vector of accounts value: VecValue.

So now bank is the owner of Bank Value

So now we go to the bank binding and look at the value it owns, which is VecValue and with the second line we are now saying we want to move it to 'accounts' binding. Then on the next line we look at bank.accounts, which is looking at the 'bank' binding, specifically at the 'accounts' field and NO VALUE and so we end up getting an error. So just about everything can own a value, not just variables, but a field on a struct, a vector can own a value.

As usual on the first line we are creating a brand new value and a string value as well and we eventually get back an account value. So we take the String Value and put it into the new function and get back the Account Value that is a struct that has a holder field.

So we take the entire Account Value and assign it to 'account' binding. Then on the next line we call print_account(account); and we pass in whatever value is owned by the account binding so it moves down to 'print_account' function. And then finally the print line statement we are looking at whatever is currently being held by the account binding but there is nothing there.

Now we are taking one field off this struct and moving it to the print_holder() function and we tried to move the entire original account struct.

So once again we create our value, a String value that we place inside the Account struct and then take that entire value and assign it to the 'account' binding. Then on the next line down we call print_holder(account.holder);. We can imagine that we are going to the account binding and whatever value is owned by that and looking at the holder field and whatever value is there we move it to print_holder function. Then on the next line when we call print_account(account);, we still have a value inside the account binding with the holder field, its just that a portion has already been moved out and you might think that this kind of works but Rust does not want you to use values that have been partially moved.

So when we try to print account they see a value there but does it have all its required fields? No, we removed a portion of it.

We moved a part of the data out so we cannot use this entire thing.

There is a lot of variation and a lot of corner cases and we have to visualize it like in this wiki. It will go a long way towards helping understand ownership.