Move

s1 is moved to s2. s1 is no longer valid:

let s1 = String::from("hello");
let s2 = s1;

println!("{}, world!", s1);

Clone

To solve this problem tt’s possible to clone:

let s1 = String::from("hello");
let s2 = s1.clone();

println!("s1 = {}, s2 = {}", s1, s2);

Ownership and Functions

Moving variable into a functiontion:

let s = String::from("hello");  // s comes into scope
takes_ownership(s);     // s's value moves into the function...
                        // ... and so is no longer valid here

Return Values and Scope

There is one possible solution: function can take anr return ownership:

fn main() {
    let s1 = gives_ownership();         // gives_ownership moves its return
                                        // value into s1

    let s2 = String::from("hello");     // s2 comes into scope

    let s3 = takes_and_gives_back(s2);  // s2 is moved into
                                        // takes_and_gives_back, which also
                                        // moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 was moved, so nothing
  // happens. s1 goes out of scope and is dropped.

fn gives_ownership() -> String {             // gives_ownership will move its
                                             // return value into the function
                                             // that calls it

    let some_string = String::from("yours"); // some_string comes into scope

    some_string                              // some_string is returned and
                                             // moves out to the calling
                                             // function
}

// This function takes a String and returns one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
                                                      // scope

    a_string  // a_string is returned and moves out to the calling function
}

Rust does let us return multiple values using a tuple, as shown here:

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(); // len() returns the length of a String

    (s, length)
}

References and Borrowing

We can pass reference instand of variable

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

It’s not possible to change value by reference. This code won’t work:

fn main() {
    let s = String::from("hello");

    change(&s);
}

fn change(some_string: &String) {
    some_string.push_str(", world"); // !error
}

Mutable References

Example:

fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

Important restriction: if you have a mutable reference to a value, you can have no other references to that value.

This work work:

 let mut s = String::from("hello");

    let r1 = &mut s;
    let r2 = &mut s; // error

    println!("{}, {}", r1, r2);

Dangling References

This code will cause an error:

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String { // dangle returns a reference to a String

    let s = String::from("hello"); // s is a new String

    &s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped. Its memory goes away.
  // Danger!

The Slice Type

A string slice is a reference to part of a String, and it looks like this:

fn main() {
    let s = String::from("hello world");

    let hello = &s[0..5];
    let world = &s[6..11];
}

This code won’t work:

fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s);

    s.clear(); // error! we try to change and we have slice 
               //(which is immutable reference by it's nature)

    println!("the first word is: {}", word);
}

String literals

let s = "Hello, world!";

The type of s here is &str: it’s a slice pointing to that specific point of the binary. This is also why string literals are immutable; &str is an immutable reference.