Portal/Notes πŸ“
RustRustlings_exercise

Move Semantics

Versi Bahasa Indonesia. Baca dalam Bahasa Inggris

  • Setiap nilai di Rust memiliki seorang pemilik (owner).
  • Hanya boleh ada satu owner pada satu waktu.
  • Ketika owner keluar dari scope, nilai tersebut akan di-drop.
  • Ketika menetapkan nilai ke variabel lain atau mengirimkannya ke fungsi, kepemilikan (ownership) ditransfer (dipindahkan/moved).
  • Borrowing memungkinkan kamu mengakses nilai tanpa mentransfer kepemilikan, menggunakan references (&).
  • Kamu hanya dapat memiliki satu mutable reference atau sejumlah immutable reference pada satu waktu.
  • Referensi:

move_semantics1.rs

// TODO: Fix the compiler error in this function.
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    let mut vec = vec;

    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics1() {
        let vec0 = vec![22, 44, 66];
        let vec1 = fill_vec(vec0);
        assert_eq!(vec1, vec![22, 44, 66, 88]);
    }
}
  • Di latihan ini fungsi fill_vec mencoba mengubah variabel vec.
  • Tapi ia mendapat compile error karena vec tidak mutable.
  • Saat mengirimkan vec0 ke dalam fungsi fill_vec, ia juga mentransfer atau memindahkan kepemilikan dari fungsi main ke fungsi fill_vec.
  • Jadi fill_vec sebagai owner dapat melakukan apa saja dengannya termasuk mengubah mutability.
  • Maka kita dapat dengan mudah menambahkan mutable di sini let mut vec = vec; untuk memperbaiki kode.
  • Dan itu membuat vec menjadi mutable dan kita dapat melakukan push nilai ke dalamnya.

move_semantics2.rs

fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    let mut vec = vec;

    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    // TODO: Make both vectors `vec0` and `vec1` accessible at the same time to
    // fix the compiler error in the test.
    #[test]
    fn move_semantics2() {
        let vec0 = vec![22, 44, 66];

        let vec1 = fill_vec(vec0.clone()); // pass cloned vec0

        assert_eq!(vec0, [22, 44, 66]);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}
  • Di latihan ini tugasnya adalah membuat vec0 dan vec1 dapat diakses pada waktu yang bersamaan.

  • Jika kita mengirimkan vec0 ke fungsi fill_vec maka ia akan mentransfer atau memindahkan kepemilikan.

  • Itu membuat variabel vec0 menjadi tidak valid dan kita mendapatkan error:

    borrow of moved value: `vec0`
  • Jadi alih-alih mengirimkan vec0, kita mengirimkan clone dari vec0.

  • Itu membuat vec0 dan vec1 tetap valid.

move_semantics3.rs

// TODO: Fix the compiler error in the function without adding any new line.
fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> { 
    //      ^^^ add mut
    vec.push(88);

    vec
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn move_semantics3() {
        let vec0 = vec![22, 44, 66];
        let vec1 = fill_vec(vec0);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}
  • Latihan ini mirip dengan move_semantics1.rs.
  • Tapi alih-alih mengubah mutability dengan mendeklarasikan ulang variabel dengan mut, kita melakukannya di dalam parameter fungsi.

move_semantics4.rs

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    // TODO: Fix the compiler errors only by reordering the lines in the test.
    // Don't add, change or remove any line.
    #[test]
    fn move_semantics4() {
        let mut x = Vec::new();
        let y = &mut x;
        y.push(42); // move this line above z
        let z = &mut x;
        z.push(13);
        assert_eq!(x, [42, 13]);
    }
}
  • Kamu hanya dapat memiliki satu mutable reference atau sejumlah immutable reference pada satu waktu.

  • Jadi kode asli memiliki compile error karena x memiliki lebih dari satu mutable reference.

    error[E0499]: cannot borrow `x` as mutable more than once at a time
      --> exercises/06_move_semantics/move_semantics4.rs:13:17
       |
    12 |         let y = &mut x;
       |                 ------ first mutable borrow occurs here
    13 |         let z = &mut x;
       |                 ^^^^^^ second mutable borrow occurs here
    14 |         y.push(42);
       |         - first borrow later used here
  • Dengan memindahkan y.push(42); ke atas let z = &mut x; kita dapat memperbaikinya.

  • Karena y sudah selesai dengan push-nya, maka x bebas dan dapat dipinjam oleh z di langkah selanjutnya.

move_semantics5.rs

#![allow(clippy::ptr_arg)]

// TODO: Fix the compiler errors without changing anything except adding or
// removing references (the character `&`).

// Shouldn't take ownership
// add & to borrow instead
fn get_char(data: &String) -> char {
    data.chars().last().unwrap()
}

// Should take ownership
fn string_uppercase(mut data: String) {
    data = data.to_uppercase();

    println!("{data}");
}

fn main() {
    let data = "Rust is great!".to_string();

    get_char(&data);

    string_uppercase(data);
}
  • Jika kita lihat komentarnya, fungsi get_char seharusnya tidak mengambil kepemilikan tetapi kode asli melakukannya.
  • Jadi kita hanya perlu menambahkan reference & pada parameter data: &String dan mengirimkan &data saat memanggil get_char.
  • Itu membuatnya meminjam (borrow) alih-alih memindahkan (move).
  • Untuk string_uppercase hapus reference dari parameter data karena kita ingin memindahkan kepemilikan ke fungsi tersebut dan hapus juga reference saat memanggilnya.

Edit on GitHub

Last updated on

Move Semantics | Faisal Affan