External crates
External crate artinya adalah "crate yang dibuat oleh orang lain".
Pada bagian ini, Anda hampir perlu menginstall Rust, namun kita masih bisa cukup menggunakan Playground. Sekarang kita akan mempelajari bagaimana cara melakukan import crates yang dibuat oleh orang lain. Ini sangatlah penting di Rust karena dua alasan:
- Sangatlah mudah untuk mengimport crates, dan
- Standard library yang dimiliki oleh Rust sangatlah kecil.
Artinya, adalah normal di Rust untuk memasukkan sebuah external crate untuk menggunakan beberapa basic function. Jika kita bisa dengan mudah menggunakan external crates, maka Anda bisa memilih crate yang paling terbaik. Mungkin seseorang akan membuat sebuah crate untuk sebuah function, dan kemudian ada orang lain yang membuat function serupa yang lebih baik.
Di buku ini, kita hanya akan mengulas crates yang paling populer, crates yang mana semua orang yang menggunakan Rust tahu.
Untuk mulai mempelajari external crates, kita akan mulai dengan crate yang paling umum digunakan: rand
.
rand
Apakah Anda menyadari sejauh ini kita belum ada menggunakan angka random? Itu dikarenakan angka random tidak berada di dalam standard library. Tapi ada banyak crate yang "hampir menjadi standard library" karena semua orang menggunakannya. Bagaimanapun, adalah hal yang mudah untuk memasukkan dan menggunakan sebuah crate. Jika Anda memiliki Rust pada komputer Anda, ada file yang bernama Cargo.toml
yang menyimpan informasi tentang crate. File Cargo.toml
terlihat seperti ini pada awalnya:
[package]
name = "rust_book"
version = "0.1.0"
authors = ["David MacLeod"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
Sekarang, jika Anda ingin menambahkan crate rand
, cari cratenya di crates.io
, yang mana adalah tempat semua crate dipost. Ia akan mengarahkanmu ke https://crates.io/crates/rand
. Dan di saat Anda mengkliknya, Anda bisa melihat screen yang bertuliskan Cargo.toml rand = "0.7.3"
. Yang perlu Anda lakukan adalah menambahkannya setelah [dependencies], seperti ini:
[package]
name = "rust_book"
version = "0.1.0"
authors = ["David MacLeod"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.7.3"
Dan Cargo akan melakukan sisanya untuk Anda. Kemudian Anda bisa mulai menulis code seperti code contoh yang ada pada website dokumentasi rand
. Untuk mendapatkan dokumentasinya Anda bisa klik pada tombol docs
pada laman di crates.io.
Jadi cukup berbicara tentang Cargo: kita tetap menggunakan Playground. Beruntungnya, Playground telah terinstall 100 crate teratas (yang sering digunakan). Sehingga Anda tidak perlu menuliskannya di dalam Cargo.toml
. Pada Playground Anda bisa membayangkan bahwa ia memiliki list yang panjang (seperti di bawah ini) dengan 100 crate terdaftar di dalamnya:
[dependencies]
rand = "0.7.3"
some_other_crate = "0.1.0"
another_nice_crate = "1.7"
Itu berarti bahwa untuk menggunakan rand
, Anda bisa melakukan hal seperti ini.
use rand; // Ini berarti seluruh dari crate rand // Pada komputer Anda, Anda tidak bisa langsung menulisnya seperti ini; // Anda perlu menuliskannya di dalam file Cargo.toml terlebih dahulu fn main() { for _ in 0..5 { let random_u16 = rand::random::<u16>(); print!("{} ", random_u16); } }
Ia akan mencetak angka u16
yang berbeda setiap saat, seperti 42266 52873 56528 46927 6867
.
Function utama yang ada di dalam rand
adalah random
dan thread_rng
(rng artinya "random number generator"). Dan sebenarnya jika Anda melihat pada random
, ia mengatakan: "Ini sebenarnya adalah shortcut untuk thread_rng().gen()
". Jadi ia sebenarnya hanyalah thread_rng
yang melakukan hampir semua hal.
Ini adalah contoh sederhana angka random dari angka 1 sampai dengan 10. Untuk mendapatkan angka tersebut, kita menggunakan .gen_range()
di antara 1 dan 11.
use rand::{thread_rng, Rng}; // atau cukup use rand::*; jika kita cukup malas untuk menuliskannya fn main() { let mut number_maker = thread_rng(); for _ in 0..5 { print!("{} ", number_maker.gen_range(1, 11)); } }
Hasil cetaknya kira-kira seperti ini: 7 2 4 8 6
.
Dengan angka random kita bisa membuat hal-hal menarik seperti membuat karakter untuk game. Kita akan menggunakan rand
dan hal lain yang kita ketahui untuk membuatnya. Pada game ini, karakter kita memiliki enam stats, dan Anda menggunakan d6 untuk stats tersebut. d6 adalah dadu yang memberikan 1, 2, 3, 4, 5, atau 6 di saat Anda melemparkannya. Setiap karakter melempar d6 tiga kali, jadinya setiap stat nilainya berada di antara 3 dan 18.
Tapi terkadang tidak adil jika karakter kita mendapatkan nilai yang rendah seperti 3 atau 4. Misalnya, jika strength Anda hanya bernilai 3, Anda tidak bisa melakukan apapun. Jadi ada satu method dimana akan menggunakan d6 empat kali. Anda lempar dadunya empat kali, dan buang angka yang paling rendah. Sehingga, jika Anda mendapatkan 3, 3, 1, 6 maka Anda bisa simpan 3, 3, 6 = 12. Kita akan membuat method ini juga sehingga si pemain game bisa menentukannya.
Ini adalah character creator sederhana yang kita buat. Kita membuat sebuah struct Character
untuk statnya, dan bahkan mengimplementasikan Display
untuk mencetak statnya dengan cara yang kita inginkan.
use rand::{thread_rng, Rng}; // Atau cukup tuliskan use rand::*; jika kita malas menuliskannya use std::fmt; // digunakan di impl Display untuk character yang kita buat struct Character { strength: u8, dexterity: u8, // ini adalah "kecepatan" constitution: u8, // ini adalah "health" intelligence: u8, wisdom: u8, charisma: u8, // Ini adalah "popularitas karakter" } fn three_die_six() -> u8 { // "die" adalahsesuatu yang kita lempar untuk mendapatkan angkanya let mut generator = thread_rng(); // buat random number generator let mut stat = 0; // ini adalah totalnya for _ in 0..3 { stat += generator.gen_range(1..=6); // jumlahkan setiap dilempar } stat // Return totalnya } fn four_die_six() -> u8 { let mut generator = thread_rng(); let mut results = vec![]; // pertama-tama, taruh angka-angkanya ke dalam vec for _ in 0..4 { results.push(generator.gen_range(1..=6)); } results.sort(); // sekarang yang hasilnya seperti [4, 3, 2, 6] akan menjadi [2, 3, 4, 6] results.remove(0); // sekarang ia menjadi [3, 4, 6] results.iter().sum() // Return resultnya } enum Dice { Three, Four } impl Character { fn new(dice: Dice) -> Self { // true untuk tiga dadu, false untuk empat dadu match dice { Dice::Three => Self { strength: three_die_six(), dexterity: three_die_six(), constitution: three_die_six(), intelligence: three_die_six(), wisdom: three_die_six(), charisma: three_die_six(), }, Dice::Four => Self { strength: four_die_six(), dexterity: four_die_six(), constitution: four_die_six(), intelligence: four_die_six(), wisdom: four_die_six(), charisma: four_die_six(), }, } } fn display(&self) { // Kita bisa melakukan ini karena kita mengimplementasikan Display di bawah println!("{}", self); println!(); } } impl fmt::Display for Character { // Cukup ikuti code di https://doc.rust-lang.org/std/fmt/trait.Display.html dan ubah sedikit saja fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Your character has these stats: strength: {} dexterity: {} constitution: {} intelligence: {} wisdom: {} charisma: {}", self.strength, self.dexterity, self.constitution, self.intelligence, self.wisdom, self.charisma ) } } fn main() { let weak_billy = Character::new(Dice::Three); let strong_billy = Character::new(Dice::Four); weak_billy.display(); strong_billy.display(); }
Hasil cetaknya adalah seperti berikut:
Your character has these stats:
strength: 9
dexterity: 15
constitution: 15
intelligence: 8
wisdom: 11
charisma: 9
Your character has these stats:
strength: 9
dexterity: 13
constitution: 14
intelligence: 16
wisdom: 16
charisma: 10
Karakter yang dibuat dengan empat dadu biasanya sedikit lebih baik dalam banyak hal (statnya).
rayon
rayon
adalah crate popular yang memungkinkan Anda mempercepat code Rust yang Anda buat. Ia popular karena ia akan membuat threads tanpa perlu menuliskan thread::spawn
. Dengan kata lain, ia popular karena ia sangat efektif namun mudah untuk ditulis. Contohnya:
.iter()
,.iter_mut()
,into_iter()
di rayon ditulis seperti ini:.par_iter()
,.par_iter_mut()
,par_into_iter()
. Jadi Anda cukup menambahkanpar_
dan code Anda menjadi lebih cepat. (par artinya "parallel")
Method lain yang juga sama: .chars()
diganti dengan .par_chars()
, dan seterusnya.
Ini adalah contoh sederhana dari sebuah potongan code yang membuat komputer bekerja lebih berat:
fn main() { let mut my_vec = vec![0; 200_000]; my_vec.iter_mut().enumerate().for_each(|(index, number)| *number+=index+1); println!("{:?}", &my_vec[5000..5005]); }
Ia membuat sebuah vector dengan 200,000 item di dalamnya: semua item tersebut adalah 0. Kemudian kita panggil .enumerate()
untuk mendapatkan index setiap angka, dan mengubah setiap 0 menjadi angka indexnya. Tentunya terlalu panjang jika kita cetak semuanya, sehingga kita hanya cetak item ke-5000 sampai dengan item ke-5004. Hal ini tetaplah cepat dilakukan Rust, namun jika Anda ingin Anda bisa membuatnya lebih cepat dengan menggunakan Rayon. Codenya hampir sama:
use rayon::prelude::*; // Import rayon fn main() { let mut my_vec = vec![0; 200_000]; my_vec.par_iter_mut().enumerate().for_each(|(index, number)| *number+=index+1); // tambahkan par_ ke iter_mut println!("{:?}", &my_vec[5000..5005]); }
Dan seperti itulah cara penggunaannya. rayon
memiliki method lainnya untuk mengkostumisasi apa yang ingin kita lakukan, tetapi yang paling sederhana, cukup "tambahkan _par
untuk membuat program Anda menjadi lebih cepat".
serde
serde
adalah crate yang populer yang memungkinkan Anda untuk mengkonversi ke dan dari format seperti JSON, YAML, dll. Cara paling umum untuk menggunakannya adalah dengan membuat struct
dengan dua buah attribute di atasnya. Ia terlihat seperti ini:
#![allow(unused)] fn main() { #[derive(Serialize, Deserialize, Debug)] struct Point { x: i32, y: i32, } }
Trait Serialize
dan Deserialize
adalah trait yang membuat konversinya menjadi lebih mudah. (Hal ini pulalah yang menjadi asal-muasal dari nama serde
) Jika Anda memiliki trait tersebut pada struct Anda, maka Anda bisa memanggil method untuk mengubahnya dari/menjadi JSON, atau format lainnya.
regex
Crate regex memungkinkan Anda melakukan pencarian melalui text menggunakan regular expressions. Dengan ini Anda bisa mencocokkan sesuatu text seperti colour
, color
, colours
dan colors
hanya dengan satu pencarian. Regular expressions adalah bahasa lain yang harus Anda pelajari jika Anda ingin menggunakannya.
chrono
chrono adalah crate yang biasanya digunakan oleh programmer yang perlu berurusan dengan function-function waktu. Kita melihat standard library yang sekarang telah banyak memiliki function-function yang berhubungan dengan waktu, tapi jika Anda memerlukan lebih dari sekedar function standard, chrono
adalah crate yang bagus untuk digunakan.