Daripada mengambil kepemilikin untuk ketika dipanggil ke dalam sebuah fungsi, ada cara yaitu mereferensikan atau meminjam dengan menggunakan &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()
}

&s1 membuat referensi tetapi tidak memiliki kepemilikan , bagaiman jika kita ingin mengubah value yang dikembalikan ,tetapi tidak memiliki kepemilikan maka tidak akan bisa.

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

    change(&s);
}

fn change(some_string: &String) {
    some_string.push_str(", world"); //akan error karena tidak memiliki kepemilikan
}

Mutable References

fixing code sebelumnya

fn main() {
    let mut s = String::from("hello");
    println!("{s}");
    change(&mut s);
    println!("{s}")
}

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

Mutable memiliki satu larangan besar. jika memiliki referensi ke sebuah nilai, kamu tidak boleh mereferensikan pada nilai lainya.

contoh:

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

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

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

mirip dengan concept race condition , memiliki 3 kemungkinan yaitu:

Larangan lainya , kita juga tidak boleh mempunyai mutable dan immutable secara bersamaan

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

    let r1 = &s; // no problem
    let r2 = &s; // no problem
    let r3 = &mut s; // BIG PROBLEM

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

alternatifnya :

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

    let r1 = &s; // no problem
    let r2 = &s; // no problem
    println!("{} and {}", r1, r2);
    // variables r1 and r2 will not be used after this point

    let r3 = &mut s; // no problem
    println!("{}", r3);
}

Dangling References

In languages with pointers, it’s easy to erroneously create a dangling pointer —a pointer that references a location in memory that may have been given to someone else—by freeing some memory while preserving a pointer to that memory. In Rust, by contrast, the compiler guarantees that references will never be dangling references: if you have a reference to some data, the compiler will ensure that the data will not go out of scope before the reference to the data does.

Contoh error karena referensi berada di scope fungsi, seperti kode dibawah:

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!

solusi: hilangkan referensi dan berikan ownership

fn main() {
    let reference_to_nothing = no_dangle();
    println!("{reference_to_nothing}")
}
fn no_dangle() -> String {
    let s = String::from("hello");

    s
}