The dbg! macro and .inspect

dbg! adalah macro yang sangat berguna yang mencetak quick information. Ini adalah alternatif yang baik dari println! karena ia sangat singkat untuk ditulis dan memberikan lebih banyak informasi:

fn main() {
    let my_number = 8;
    dbg!(my_number);
}

Maka ia mencetak [src\main.rs:4] my_number = 8.

Tapi sebenarnya, Anda bisa meletakkan dbg! di tempat lainnya, dan bahkan membungkus code didalamnya. Lihat code ini sebagai contoh:

fn main() {
    let mut my_number = 9;
    my_number += 10;

    let new_vec = vec![8, 9, 10];

    let double_vec = new_vec.iter().map(|x| x * 2).collect::<Vec<i32>>();
}

Code ini membuat sebuah angka yang mutable dan mengubahnya. Kemudian membuat sebuah vec, dan menggunakan iter dan map dan collect untuk membuat vec yang baru. Kita bisa meletakkan dbg! hampir di segala macam tempat di code ini. dbg! menanyakan kepada compiler: "Apa yang Anda lakukan saat ini?" dan memberitahukannya kepada Anda.

fn main() {
    let mut my_number = dbg!(9);
    dbg!(my_number += 10);

    let new_vec = dbg!(vec![8, 9, 10]);

    let double_vec = dbg!(new_vec.iter().map(|x| x * 2).collect::<Vec<i32>>());

    dbg!(double_vec);
}

Ia akan mencetak:

[src\main.rs:3] 9 = 9

dan:

[src\main.rs:4] my_number += 10 = ()

dan:

[src\main.rs:6] vec![8, 9, 10] = [
    8,
    9,
    10,
]

dan ini, yang bahkan menunjukkan value dari sebuah ekspresi:

[src\main.rs:8] new_vec.iter().map(|x| x * 2).collect::<Vec<i32>>() = [
    16,
    18,
    20,
]

dan:

[src\main.rs:10] double_vec = [
    16,
    18,
    20,
]

.inspect agak mirip dengan dbg!, namun Anda menggunakannya seperti map di dalam sebuah iterator. Ia memberikan Anda item dari iterator dan Anda bisa mencetaknya atau melakukan apapun yang Anda inginkan. Sebagai contoh, mari kita lihat double_vec lagi.

fn main() {
    let new_vec = vec![8, 9, 10];

    let double_vec = new_vec
        .iter()
        .map(|x| x * 2)
        .collect::<Vec<i32>>();
}

Kita ingin mengetahui lebih banyak informasi tentang apa yang dilakukan code tersebut. Jadi kita tambahkan inspect() di dua tempat:

fn main() {
    let new_vec = vec![8, 9, 10];

    let double_vec = new_vec
        .iter()
        .inspect(|first_item| println!("The item is: {}", first_item))
        .map(|x| x * 2)
        .inspect(|next_item| println!("Then it is: {}", next_item))
        .collect::<Vec<i32>>();
}

Outputnya adalah:

The item is: 8
Then it is: 16
The item is: 9
Then it is: 18
The item is: 10
Then it is: 20

Dan karena .inspect mengambil sebuah closure, kita bisa menulisnya sebanyak yang kita inginkan:

fn main() {
    let new_vec = vec![8, 9, 10];

    let double_vec = new_vec
        .iter()
        .inspect(|first_item| {
            println!("The item is: {}", first_item);
            match **first_item % 2 { // first_item adalah &&i32, jadinya kita menggunakan **
                0 => println!("It is even."),
                _ => println!("It is odd."),
            }
            println!("In binary it is {:b}.", first_item);
        })
        .map(|x| x * 2)
        .collect::<Vec<i32>>();
}

Outputnya adalah:

The item is: 8
It is even.
In binary it is 1000.
The item is: 9
It is odd.
In binary it is 1001.
The item is: 10
It is even.
In binary it is 1010.