วันนี้ขอมาเป็นแนวสรุปความประทับใจ หลังจากได้ลองเขียน Rust แบบคร่าวๆ เรียกว่าคร่าวแบบ แตะ ๆ พอให้รู้ฟีลลิ่งในการเขียนโดยจะยังไม่ได้ลงอะไรลึกมากสักเท่าไร
ในฐานะที่งานของตัวเอง จะใช้ python เป็นหลัก และอยากจะเปิดโลกใหม่ ๆ ให้ตัวเองบ้าง ก็เลยลองจับ Rust มาเขียนเล่น ๆ ดู เพื่อให้รู้จักวิธีการเขียนที่ตัวเองไม่คุ้นเคยดูบ้าง
โดย codebase ที่ได้ลองก็เป็น Project เริ่มต้นที่เชื่อว่าใครหลายคนที่เริ่มต้นกับการเขียนโปรแกรมแทบจะทุกภาษา จะต้องเคยได้ลองเขียนสิ่งนี้กัน
นั่นก็คือ ลองเขียน mini game ทายตัวเลขนั่นเอง ซึ่งโจทย์ของเกมนี้ก็ simple แบบสุด ๆ 1. สุ่มตัวเลขมาตัวนึงเพื่อเป็นเลขสำหรับการทาย 2. รอรับตัวเลข จาก user input 3. เอาตัวเลขไป compare เพื่อจะบอก User ว่ามากไปหรือน้อยไป 4. ถ้าตัวเลขตรงกันก็จะขึ้นข้อความ "You win" และจบเกม
เริ่ม
จะขอข้ามส่วนของการ build project แบบ fast forward ไปเลยแล้วกันนะครับ เรามาดูในส่วนของไฟล์หลักของตัวโปรแกรมกัน ซึ่งในการเขียนนี้ ผมเขียนโดยเอาส่วนประกอบทั้งหมดมา pack อยู่ในไฟล์เดียวกันคือ main.rs แค่ไฟล์เดียว
main.rs
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { println!("Guess the number!"); let secret_number = rand::thread_rng().gen_range(1..=100); println!("The secret number is: {secret_number}"); loop { println!("Please input your guess."); let mut guess = String::new(); io::stdin() .read_line(&mut guess) .expect("Failed to read line"); let guess: u32 = match guess .trim() .parse() { Ok(num) => num, Err(_) => { println!("Please enter a valid number."); continue; } }; println!("You guessed: {guess}"); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => { println!("You win!"); break; } } } }
ถ้าใครลองเอาไฟล์ main นี้ไปรันดู ก็จะได้ mini game ขึ้นมาทันที 1 เกมไปเลย ทีนี้ ขอมาเจาะแต่ละส่วน ว่ามีส่วนไหนที่ประทับใจกับการลองเขียนครั้งนี้บ้าง
ความประทับใจที่ 1 : การประกาศตัวแปร
ส่วนแรกที่รู้สึกว่ามันเจ๋งดี คือการประกาศตัวแปร
let secret_number = rand::thread_rng().gen_range(1..=100); . . let mut guess = String::new();
จะเห็นได้ว่า 2 ส่วนหลักที่แตกต่างกันระหว่าง 2 บรรทัดนี้คือ
let mut
กับlet
ซึ่งการประกาศตัวแปรของ Rust จะมี default behavior เป็นตัวแปรแบบ immutable = ตัวแปรที่ไม่สามารถเปลี่ยนแปลงค่าได้ แต่ถ้าเราต้องการประกาศตัวแปรที่สามารถเปลี่ยนแปลงค่าได้ระหว่าง runtime (ซึ่งในที่นี้ คือ ตัวแปรที่ใช้รับ user input) เราจะใช้การประกาศตัวแปรที่จะระบุไปว่าเป็น แบบ mutable ซึ่งจะประกาศเป็นแบบนี้let mut guess = String::new();
ก็จะเป็นการประกาศตัวแปร guess เป็น String ที่สามารถเปลี่ยนแปลงค่าได้ระหว่าง runtime
ความประทับใจที่ 2 : Error handling
การทำ error handling ที่ถือว่าดีงามมาก ๆ เป็นการดักให้ dev ไม่เขียนหลุดไปได้ ถ้าไม่มีการทำ error handling เอาไว้
io::stdin() .read_line(&mut guess) .expect("Failed to read line"); . . let guess: u32 = match guess .trim() .parse() { Ok(num) => num, Err(_) => { println!("Please enter a valid number."); continue; } };
จากโค้ดชุดนี้ จะเห็นว่าเป็นการรอรับ input จาก user และก็นำไป trim และแปลงค่าให้เป็นตัวเลข เพื่อจะนำไปใช้ในการ compare ต่อ
ซึ่งจะเห็นได้ว่า มีโค้ดส่วนที่เป็น
.expect()
อยู่ ในส่วนนี้ เราเป็นการเรียก function .read_line() ซึ่ง Rust compiler จะบังคับเราให้มีการทำ error handling เอาไว้ด้วย เพราะถ้าเราไม่ได้เขียน ‘expect()’ เอาไว้ compiler ก็จะขึ้น warning มาให้เราแบบนี้17 | / io::stdin() 18 | | .read_line(&mut guess); | |__________________________________^ | = note: this `Result` may be an `Err` variant, which should be handled = note: `#[warn(unused_must_use)]` on by default
ซึ่งก่อนอื่นเราต้องมาเข้าใจกันก่อน ว่าฟังก์ชันจะมีการ return ได้ 2 รูปแบบ คือ Ok และ Err
โดย Compiler จะบังคับให้เราต้องทำ Error handling เอาไว้ แม้เราจะมั่นใจมากแค่ไหนก็ตามว่า User จะไม่กรอกข้อมูลในส่วนนี้มาผิด
ส่วนนี้ถ้าเทียบกับ python โค้ดในส่วนนี้ก็จะสามารถรันต่อไปได้แม้จะไม่ได้ดัก error ไว้ก็ตามที
ซึ่งเราจะรอดจาก compiler ไปไม่ได้ในกรณีนี้… นับเป็นอีกหนึ่งความดีงามที่ประทับใจจจ
ความประทับใจ(??)ที่ 3 : u32 !??
u32 = The 32-bit unsigned integer type โอ้โหหหหหหห เจอการประกาศตัวแปรแบบนี้เข้าไป ถึงกับอึ้งไปเลย 5555 ปกติจะเป็นการประกาศตัวแปรแบบ int, float, double อันนี้นี่มาเหนือสุด ๆ แต่เอาจริง ๆ ก็ทั้งรู้สึกว่าประทับใจ ปนกับรู้สึกว่ามันเข้าใจยากไปมั้ย สำหรับคนที่เพิ่งมาเขียนโปรแกรม?
แต่ข้อดีของมันก็คือมันโคตรจะตรงไปตรงมาจัด ๆ Unsigned 32 bit —> u32 คือถ้าอย่างเป็น int, float เราต้องมาจำเอาเองอีกว่ามัน limit ที่กี่ bit การประกาศตัวแปรของ Rust เรียกได้ว่าจบเลย ไม่ต้องรู้อะไรเพิ่มอีกแล้ว แค่จำให้ได้ก็พอว่าต้องประกาศด้วย keyword อะไร 555
ความประทับใจที่ 4 : cargo doc
ถ้าใครพอจะมี project ตัวอย่าง หรือเคยลองเขียนมาบ้าง ลองไปรันคำสั่งนี้ดูที่ project path
cargo doc --open
โหหหห ผมตื่นเต้นกับสิ่งนี้มาก ตัว compiler จะ generate webpage ขึ้นมา และแจกแจงทุก ๆ dependencies ที่เราใช้อยู่ใน project นั้น ๆ เป็น doc refernce แบบไม่ต้องไปนั่งหาเลยว่า dependencies ที่เราเรียกใช้ใน project มีวิธีการเขียนยังไง หรือต้องรับ-ส่ง ตัวแปรอะไรบ้าง
อันนี้คือโคตรจะดีงามจริง ๆ จะมาบอกว่าหา doc reference ไม่เจอไม่ได้แล้วนะ งานนี้
ก็ประมาณนี้ครับ กับการลองเขียน Rust แบบเตาะแตะแรกเริ่มของผม ไว้มีประเด็นอะไรที่ได้เรียนรู้เพิ่มเติม แล้วจะยกมาคุยกันต่อนะครับผมมม
>_JV
