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
}
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);
}
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
}