diff --git a/docs/basic/attributes.md b/docs/basic/attributes.md index 78987319..27ba618f 100644 --- a/docs/basic/attributes.md +++ b/docs/basic/attributes.md @@ -22,6 +22,8 @@ Outer attribute dituliskan tepat sebelum target (crate, module, module item, ata - `#[attribute = "value"]` - `#[attribute(key = "value")]` - `#[attribute(value)]` +- `#[attribute(not(key = "value"))]` untuk operasi **NOT** +- `#[attribute(not(value))]` untuk operasi **NOT** Contoh penerapan: @@ -40,6 +42,8 @@ Sedikit berbeda dengan inner attribute, penulisannya berada di dalam target (cra - `#![attribute = "value"]` - `#![attribute(key = "value")]` - `#![attribute(value)]` +- `#![attribute(not(key = "value"))]` untuk operasi **NOT** +- `#![attribute(not(value))]` untuk operasi **NOT** Rust mengenal beberapa jenis attributes, dan kita akan membahasnya satu per satu. @@ -163,7 +167,7 @@ Bisa dilihat, hasilnya program tereksekusi tanpa error. Enum `Superhero` kini me ## A.49.3. Attribute `cfg` / *configuration* -Attribute `cfg` digunakan untuk menentukan beberapa konfigurasi yang berhubungan dengan arsitekture hardware/prosesor. +Attribute `cfg` digunakan untuk operasi-operasi yang berhubungan dengan target arsitekture hardware/prosesor, misalnya seperti conditional compilation ketika OS adalah linux, dan lainnya. Salah satu contoh penerapannya bisa dilihat pada kode berikut. Ada 2 buah module yang namanya sama persis, perbedaannya adalah satu didefinisikan khusus untuk platform `linux`, dan satunya lagi untuk platform `windows`. Hal seperti ini bisa dilakukan menggunakan attribute `cfg` dengan key `target_os`. @@ -246,9 +250,83 @@ Opsi value yang tersedia: - `arm` - `aarch64` +### ◉ Macro `cfg!()` dan conditional compilation + +Attribute `cfg` juga tersedia versi macro-nya, yaitu `cfg!()`. Macro ini kegunaannya sama seperti attribute `cfg`, perbedaannya macro `cfg!()` mengembalikan nilai boolean, yang darinya bisa dikombinasikan dengan seleksi kondisi untuk keperluan conditional compilation. Contoh penggunaan macro `cfg!()`: + +```rust +fn main() { + #[cfg(target_os = "linux")] + { + println!("hello linux. from attribute cfg") + } + + #[cfg(target_os = "windows")] + { + println!("hello windows. from attribute cfg") + } + + if cfg!(target_os = "linux") { + println!("hello linux. from macro cfg!()"); + } else if cfg!(target_os = "windows") { + println!("hello windows. from macro cfg!()"); + } +} +``` + +Penjelasan: + +- Kode block `#[cfg(target_os = "linux")]` hanya dieksekusi ketika program dijalankan di Linux. +- Kode block `#[cfg(target_os = "windows")]` hanya dieksekusi ketika program dijalankan di Windows. +- Seleksi kondisi `cfg!(target_os = ...)` merupakan alternatif penulisan 2 kode sebelumnya yang digabung menjadi 1 rantai seleksi kondisi. + - Kondisi `cfg!(target_os = "linux")` terpenuhi ketika program dijalankan di Linux + - Kondisi `cfg!(target_os = "windows")` terpenuhi ketika program dijalankan di Windows + +Output program ketika dijalankan di komputer penulis yang menggunakan Windows: + +![Attribute](img/attribute-4.png) + +> Lebih detailnya mengenai macro akan dibahas di chapter terpisah. + +### ◉ Configuration `debug_assertions` + +By default, Rust menggunakan profil kompilasi **debug** saat eksekusi command `cargo run`. Di kode program, penanda apakah profil kompilasi debug digunakan atau tidak bisa dilihat dari nilai konfigurasi `#[cfg(debug_assertions)]` via attribute, dan `cfg!(debug_assertions)` via macro. + +Nilai `cfg!(debug_assertions)` selalu bernilai `true` kecuali command yang digunakan saat eksekusi program adalah `cargo run --release`. Flag `--release` saat eksekusi program membuat nilai `debug_assertions` menjadi `false`. + +Contoh penerapan: + +```rust +fn main() { + #[cfg(debug_assertions)] + { + println!("debug mode. from attribute cfg") + } + + #[cfg(not(debug_assertions))] + { + println!("release mode. from attribute cfg") + } + + if cfg!(debug_assertions) { + println!("debug mode. from macro cfg!()"); + } else { + println!("release mode. from macro cfg!()"); + } +} +``` + +Output eksekusi program menggunakan command `cargo run` vs `cargo run --release`. + +![Attribute](img/attribute-5.png) + +Pada profil release, kode program dikompilasi sekaligus dioptimisasi. Penggunaan profil ini dianjurkan untuk distribusi production binary. + +> Di beberapa bahasa pemrograman lain deteksi profile dilakukan mengunakan kombinasi keyword `if` dan nilai environment variable (`ENV`). Dari situ bisa dilihat apakah environment yang digunakan adalah production, staging, atau local. + ### ◉ Other configuration -Ada beberapa key konfigurasi lainnya yang tersedia. Lebih detailnya silakan lihat di https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options. +Ada beberapa key konfigurasi lainnya yang tersedia. Lebih detailnya silakan lihat di https://doc.rust-lang.org/reference/conditional-compilation.html ## A.49.4. Attribute *linting* & *diagnostic* @@ -256,7 +334,7 @@ Ada beberapa attribute name yang bisa digunakan untuk meng-override *default lin Contoh kasus yang berhubungan dengan *linting* bisa dilihat pada kode berikut. -![Attribute](img/attribute-4.png) +![Attribute](img/attribute-6.png) Kode di atas tidak menghasilkan error. Kode akan dieksekusi tanpa error. Namun ada 3 buah warning yang muncul karena beberapa baris kode tidak digunakan atau sia-sia. @@ -275,6 +353,17 @@ fn say_something() { println!("how are you") } +pub mod m1 { + #[allow(missing_docs)] + pub fn undocumented_one() -> i32 { 1 } + + #[warn(missing_docs)] + pub fn undocumented_too() -> i32 { 2 } + + // #[deny(missing_docs)] + // pub fn undocumented_end() -> i32 { 3 } +} + fn main() { #[allow(unused_variables)] let name = "noval agung"; @@ -283,15 +372,18 @@ fn main() { } ``` -Pada kode di atas, attribute name `allow` digunakan pada 3 tempat: +Pada kode di atas, ada beberapa attribute yang digunakan: - `#[allow(unused_imports)]` digunakan untuk antisipasi error yang muncul ketika module item di-import namun tidak digunakan. - `#[allow(dead_code)]` digunakan untuk membolehkan kode yang tidak digunakan. - `#[allow(unused_variables)]` digunakan untuk membolehkan variabel yang didefinisikan tapi tidak dimanfaatkan. +- `#[allow(missing_docs)]` membolehkan kode di bawahnya untuk tidak memiliki komentar/dokumentasi. +- `#[warn(missing_docs)]` memunculkan warning jika kode di bawahnya tidak memiliki komentar/dokumentasi. +- `#[deny(missing_docs)]` memunculkan error jika kode di bawahnya tidak memiliki komentar/dokumentasi. Kode ini sengaja di-remark agar eksekusi program tidak menghasilkan error. Dengan penambahan 3 attribute di atas program akan tereksekusi tanpa warning. -![Attribute](img/attribute-5.png) +![Attribute](img/attribute-7.png) Ada beberapa attribute *key* yang bisa digunakan untuk override *lint* warning: @@ -299,7 +391,25 @@ Ada beberapa attribute *key* yang bisa digunakan untuk override *lint* warning: - `#[warn(lint_rule)]` untuk memunculkan warning untuk suatu *lint rule* yang *default*-nya tidak memunculkan warning.
List `lint_rule` bisa dilihat di https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html. -- `#[deny(lint_rule)]` atau `#[forbid(lint_rule)]` untuk melarang suatu *lint rule* yang *default*-nya adalah diperbolehkan.
List `lint_rule` bisa dilihat di https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html. +- `#[deny(lint_rule)]` untuk melarang suatu *lint rule* yang *default*-nya adalah diperbolehkan.
List `lint_rule` bisa dilihat di https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html. + +- `#[forbid(lint_rule)]` untuk melarang suatu *lint rule* yang *default*-nya adalah diperbolehkan **dengan catatan kode beserta isi yang dituju lint tersebut tidak bisa diubah menjadi *lint rule*-nya menjadi `allow` lagi**. Penjelasan detailnya ada di https://doc.rust-lang.org/reference/attributes/diagnostics.html + + Contoh penerapan: + + ```rust + #[forbid(missing_docs)] + pub mod m3 { + #[allow(missing_docs)] + pub fn undocumented_too() -> i32 { 2 } + } + ``` + + Attribute `#[forbid(missing_docs)]` pada module `m3` menjadikan seluruh isi block module tersebut harus memiliki dokumentasi, mirip seperti penggunaan `#[deny(missing_docs)]`. + + Penggunaan `allow` di dalam block tersebut membuat eksekusi program menghasilkan error, karena meskipun attribute tersebut ditujukan untuk fungsi `undocumented_too()` pada parent block (yaitu module `m3`) sudah ditentukan aturannya menggunakan `forbid`. + + Selain 3 attribute di atas, ada juga beberapa attribute lainnya untuk keperluan *diagnostic*, di antaranya: @@ -312,7 +422,7 @@ Ada sebuah attribute bernama `non_exhaustive` gunanya untuk mem-*bypass* error y Salah satu contoh error yang dimaksud bisa dilihat pada kode berikut. Error ini muncul karena enum `Superhero::Superhero` tidak ter-cover dalam pattern matching. -![Attribute](img/attribute-6.png) +![Attribute](img/attribute-8.png) Solusi untuk mengatasi error di atas bisa dengan cukup menambahkan case kondisi yang belum ter-cover: @@ -418,7 +528,7 @@ Pada kode di atas bisa dilihat, module `util1` dan `util2` patuh mengikuti atura Jialankan program, harusnya tidak ada error. -![Attribute](img/attribute-7.png) +![Attribute](img/attribute-9.png) ## A.49.7. Attribute *testing* diff --git a/docs/basic/img/attribute-4.png b/docs/basic/img/attribute-4.png index c51f41a7..d48586e0 100644 Binary files a/docs/basic/img/attribute-4.png and b/docs/basic/img/attribute-4.png differ diff --git a/docs/basic/img/attribute-5.png b/docs/basic/img/attribute-5.png index 7f379e55..2645ec94 100644 Binary files a/docs/basic/img/attribute-5.png and b/docs/basic/img/attribute-5.png differ diff --git a/docs/basic/img/attribute-6.png b/docs/basic/img/attribute-6.png index 340791f8..c51f41a7 100644 Binary files a/docs/basic/img/attribute-6.png and b/docs/basic/img/attribute-6.png differ diff --git a/docs/basic/img/attribute-7.png b/docs/basic/img/attribute-7.png index 440aee1f..7f379e55 100644 Binary files a/docs/basic/img/attribute-7.png and b/docs/basic/img/attribute-7.png differ diff --git a/docs/basic/img/attribute-8.png b/docs/basic/img/attribute-8.png new file mode 100644 index 00000000..340791f8 Binary files /dev/null and b/docs/basic/img/attribute-8.png differ diff --git a/docs/basic/img/attribute-9.png b/docs/basic/img/attribute-9.png new file mode 100644 index 00000000..440aee1f Binary files /dev/null and b/docs/basic/img/attribute-9.png differ