Skip to content
Select theme

How to return ownership from a function

Short answer: name the owned type in the return position — fn build() -> String. Returning a value moves it out to the caller, the same way passing it in moves it the other way: a function that took a value by value hands back the same value, so return the binding, not a copy.

wrap: making the gift
main: holding "teddy bear"
dropping "teddy bear"

wrap builds a Gift, and its return type is Gift — the owned type, not &Gift. The dropping line lands at the end of main, not of wrap: the value outlived the function that made it. Whoever calls wrap owns what comes back, and that is the whole mechanism — String, Vec<T> and your own types included.

A function that takes a value by value can give it back. Both of these uppercase a string; the difference is in the buffers.

before: 0x104ce50d0
after: 0x104ce50e0
before: 0x104ce50d0
after: 0x104ce50d0

In the first pair the addresses differ: to_uppercase() built a second buffer, and the original was freed when the parameter dropped. In the second pair they match — the caller got back the buffer it handed over. The digits differ on your machine; whether the pair matches is what matters.

make_ascii_uppercase() works in place because ASCII letters are one byte each in upper and lower case; to_uppercase() covers all of Unicode, where one character can become two (“ß” is one character, “SS” is two), so it returns a new String. Hand back the binding, text, when the result is the input changed in place; a genuinely new result is honest work, not a clone.

error[E0382]: borrow of moved value: `message`
--> src/main.rs:11:16
|
7 | let message = String::from("hello");
| ------- move occurs because `message` has type `String`, which does not implement the `Copy` trait
8 | let shouted = shout_in_place(message);
| ------- value moved here
...
11 | println!("{message}");
| ^^^^^^^ value borrowed here after move
|
note: consider changing this parameter type in function `shout_in_place` to borrow instead if owning the value isn't necessary
--> src/main.rs:1:29
|
1 | fn shout_in_place(mut text: String) -> String {
| -------------- ^^^^^^ this parameter takes ownership of the value
| |
| in this function
help: consider cloning the value if the performance cost is acceptable
|
8 | let shouted = shout_in_place(message.clone());
| ++++++++
For more information about this error, try `rustc --explain E0382`.

Returning ownership doesn’t give the caller two values. message moved into shout_in_place and the value that came back lives in shouted; message was never re-initialised. rustc puts value moved here on the argument and value borrowed here after move on the printing line, because printing borrows. The note: on the parameter matches the previous page in this chapter. If you need the original afterwards, the function shouldn’t have taken it by value; the E0382 page has the fixes.

When taking it by value is the wrong shape

Section titled “When taking it by value is the wrong shape”
HELLO

Same job as the two functions above, but nothing moves: the caller keeps its name and the function works through a reference. Taking a value by value only to hand it back forces the caller to rebind, and a function that forgets the return loses the value for good. Borrowing is the Borrowing book’s subject; this page stops at the rule that the return type decides who owns what comes back.

dropping "second"
main: holding "first"
dropping "first"

An owned value moves out of an if arm the same way it moves out of the function’s tail: nothing to work around when the value is chosen inside the function. The Gift that wasn’t chosen is dropped when pick ends. Wanting -> &Gift for a value built inside the function is a different problem, and it belongs to the Lifetimes chapter.