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.
The return type is the whole mechanism
Section titled “The return type is the whole mechanism”struct Gift(String);
impl Drop for Gift { fn drop(&mut self) { println!("dropping \"{}\"", self.0); }}
fn wrap() -> Gift { println!("wrap: making the gift"); Gift(String::from("teddy bear"))}
fn main() { let gift = wrap(); println!("main: holding \"{}\"", gift.0);}wrap: making the giftmain: 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.
Handing back a value you took
Section titled “Handing back a value you took”A function that takes a value by value can give it back. Both of these uppercase a string; the difference is in the buffers.
fn shout(text: String) -> String { text.to_uppercase()}
fn shout_in_place(mut text: String) -> String { text.make_ascii_uppercase(); text}
fn main() { let first = String::from("hello"); println!("before: {:p}", first.as_ptr()); let shouted = shout(first); println!("after: {:p}", shouted.as_ptr());
let second = String::from("hello"); println!("before: {:p}", second.as_ptr()); let shouted = shout_in_place(second); println!("after: {:p}", shouted.as_ptr());}before: 0x104ce50d0after: 0x104ce50e0before: 0x104ce50d0after: 0x104ce50d0In 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.
The hand-back doesn’t duplicate
Section titled “The hand-back doesn’t duplicate”fn shout_in_place(mut text: String) -> String { text.make_ascii_uppercase(); text}
fn main() { let message = String::from("hello"); let shouted = shout_in_place(message);
println!("{shouted}"); println!("{message}");}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 functionhelp: 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”fn shout(text: &mut String) { text.make_ascii_uppercase();}
fn main() { let mut message = String::from("hello");
shout(&mut message); println!("{message}");}HELLOSame 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.
A value built inside a branch
Section titled “A value built inside a branch”struct Gift(String);
impl Drop for Gift { fn drop(&mut self) { println!("dropping \"{}\"", self.0); }}
fn pick(use_first: bool) -> Gift { let first = Gift(String::from("first")); let second = Gift(String::from("second"));
if use_first { first } else { second }}
fn main() { let chosen = pick(true); println!("main: holding \"{}\"", chosen.0);}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.
Related
Section titled “Related”- How to pass ownership of a value to a function — the move in the other direction
- How move semantics work in Rust — what happens to the bytes on a move
- How to fix error E0382: borrow of moved value — the error above, and its fixes
- Moves and ownership — the rest of this chapter
- Next in this chapter: when should you clone?