DEV Community

Cover image for [Rust Guide] 4.3. Ownership and Functions
SomeB1oody
SomeB1oody

Posted on

[Rust Guide] 4.3. Ownership and Functions

4.3.0 Before the Main Text

After learning Rust’s general programming concepts, you reach the most important part of all of Rust—ownership. It is quite different from other languages, and many beginners find it difficult to learn. This chapter aims to help beginners fully master this feature.

This chapter has three subsections:

  • Ownership: Stack Memory vs. Heap Memory
  • Ownership Rules, Memory, and Allocation
  • Ownership and Functions (this article)

If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.

4.3.1 Passing Values to Functions

In terms of semantics, passing a value to a function is similar to assigning a value to a variable, so to put it in one sentence: function parameter passing works the same way as assignment

Next, let’s explain it in detail: passing a value to a function will cause either a move or a copy.

  • For data types that implement the Copy trait, a copy occurs, so the original variable is not affected and can continue to be used.
  • For data types that do not implement the Copy trait, a move occurs, so the original variable is invalidated and cannot be used.

A detailed introduction to the Copy trait, moves, and copies was given in the previous article, 4.2. Ownership Rules, Memory, and Allocation, so it will not be repeated here.

fn main() {
    let machine = String::from("6657");
    wjq(machine);

    let x = 6657;
    wjq_copy(x);
    println!("x is: {}", x);
}

fn wjq(some_string: String) {
    println!("{}", some_string);
}

fn wjq_copy(some_number: i32) {
    println!("{}", some_number);
}
Enter fullscreen mode Exit fullscreen mode
  • For the variable machine:

    • String is a complex data type, allocated on the heap, and it does not implement the Copy trait.
    • When machine is passed to the wjq function, a move occurs, meaning ownership is transferred from the variable machine to the function parameter some_string.
    • At this point, ownership of machine has been transferred. The function wjq can use it normally, but the original variable machine is no longer available. If you try to use machine afterward, the compiler will report an error.
  • For the variable x:

    • i32 is a basic data type with a fixed size, allocated on the stack, and it implements the Copy trait.
    • When x is passed to the wjq_copy function, a copy occurs, meaning the value of x is copied and passed to the function parameter some_number.
    • Because this is just a value copy, the original variable x is unaffected and can still be used after the function call.
  • For the variable some_string:

    • Its scope starts when it is declared on line 10 and ends when the } on line 12 is reached.
    • When it leaves scope, Rust automatically calls the drop function to free the memory occupied by some_string.
  • For the variable some_number:

    • Its scope starts when it is declared on line 14 and ends when the } on line 16 is reached.
    • Nothing special happens when it leaves scope, because types that implement the Copy trait do not call Drop when they go out of scope.

4.3.2 Return Values and Scope

Ownership is also transferred during the process of returning a value from a function.

fn main() {
    let s1 = give_ownership();
    let s2 = String::from("6657");
    let s3 = takes_and_gives_back(s2);
}

fn give_ownership() -> String {
    let some_string = String::from("machine");
    some_string
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string
}
Enter fullscreen mode Exit fullscreen mode
  • The behavior of the give_ownership function:

    • The give_ownership function creates a String variable some_string, and ownership of it belongs to the give_ownership function.
    • When some_string is returned as the function’s return value, ownership is transferred to the caller, namely the variable s1.
    • As a result, some_string will not be dropped after leaving the scope of give_ownership, because its ownership has been handed over to s1.
  • The behavior of the takes_and_gives_back function:

    • The takes_and_gives_back function accepts a String parameter a_string. When the function is called, ownership of the passed-in argument (s2) is transferred to the function parameter a_string.
    • When the function returns a_string, ownership is transferred once again from a_string to the caller, namely the variable s3.
    • At this point, s2 is no longer available, because its ownership has been transferred to takes_and_gives_back, and the function’s return value is assigned to s3.

The ownership of a variable always follows the same pattern:

  • Assigning a value to another variable causes a move. Only types that implement the Copy trait, such as basic types like i32 and f64, are copied during assignment.
  • When a variable containing heap data leaves scope, its value is cleaned up by the drop function, unless ownership of the data has been moved to another variable.

4.3.3 Letting a Function Use a Value Without Taking Ownership

Sometimes the intent of the code is for a function to use a variable, but you do not want to lose the right to use the data as a result. In that case, you can write it like this:

fn main() {
    let s1 = String::from("Hello");
    let (s2, len) = calculate_length(s1);
    println!("The length of '{}' is {}", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)
}
Enter fullscreen mode Exit fullscreen mode

In this example, s1 has to give ownership to s, but when this function returns, it also returns s intact and hands ownership of the data to s2. In this way, ownership of the data is given back to a variable in the main function, allowing the data under s1 to be used again in main (even though the variable name has changed).

This approach is too troublesome and too clumsy. Rust provides a feature for this scenario called reference, which lets a function use a value without taking ownership of it. This feature will be explained in the next article.

Top comments (0)