มาหัดเขียนโปรแกรมด้วยภาษา Rust กันเถอะ
สวัสดีครับ ช่วงนี้ผมสนใจอยากเขียนภาษา Rust ก็เลยเริ่มต้นศึกษา เวลาว่างๆ วันละ ครึ่งชม. หรือ 1ชั่วโมงบ้าง แล้วแต่วัน เลยอยากจะเขียนบล็อกบันทึกไว้ สืบเนื่องจาก ได้ยินชื่อภาษานี้มาหลายปีแล้ว แต่ไม่มีโอกาสได้ใช้งาน ก็เลยผ่านไป
แต่ช่วงนี้เป็นช่วงที่เริ่มมีเวลาศึกษามากขึ้น อาจจะเพราะว่าหยุดเขียนโค๊ดไปนาน ช่วงนี้มันเลยมีแรงจูงใจนิดนึง ตรงที่รู้สึกว่าเราไม่รู้อะไรเต็มไปหมดเลย ก็เลยอยากจะลองหัด Rust ซะ ซึ่งจริงๆแล้วช่วงนี้ผมหัดไปทั่วมากครับ ลองๆให้หมด ทั้ง Solidity / Blockchain กลับไปอ่าน C/C++ นั่งโค๊ด Python เล่นๆ แล้วค่อยมาดูอีกทีว่าจะโฟกัส หรือลงลึกไปที่ภาษาไหน ซึ่งมันก็ขึ้นอยู่กับตัวงานด้วย😅
ติดตั้ง Rustup
สำหรับ Mac OS และ Unix นั้นติดตั้งง่ายมากๆ เข้าไปในเว็บ rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
ส่วน Windows จะชื่อไฟล์ rustup-init.exe
ดาวน์โหลดมา Install ได้เลย เป็น Script ที่ติดตั้ง package และจัดการ Path ให้เราเรียบร้อย ไม่ต้องทำอะไรเลย แค่ restart ตัว cmd.exe หรือ Powershell ก็สามารถใช้งาน Rust ได้แล้ว
เมื่อติดตั้งเสร็จเราจะได้ทั้ง rustc
ที่เป็น Compiler, Cargo
ที่เป็น Package Manager และ rustup
มาพร้อมๆกันเลย
ทดสอบดูว่า ติดตั้ง Rustup เรียบร้อย พร้อม rustc
ที่ใช้งานได้
rustc --version
# เวอร์ชั่น ณ วันที่เขียนบทความ
rustc 1.59.0 (9d1b2106e 2022-02-23)
ไฟล์ config ของ Rust environment จะอยู่ที่
~/.cargo/bin
ส่วน Windows ก็คือ%USERPROFILE%\.cargo\bin
หรือหากเราเคยติดตั้ง Rustup มาแล้ว อยากจะอัพเดท ก็สามารถอัพเดทได้ด้วยคำสั่ง
rustup update
Text Editor
แน่นอน VS Code น่าจะกลายเป็น standard และคนนิยมที่สุดแล้วครับ ส่วน Extension ก็ลง Rust-Analyzer
แต่ถ้าใครใช้ IDE อย่างเช่น ของ JetBrains ก็ต้องใช้ตัวนี้ Plugin Rust (คิดว่าน่าจะใช้ได้ทั้ง CLion และ IntelijIDEA)
Hello World แรก
ทดลองเขียนโปรแกรมแรกกันเลย ตั้งชื่อไฟล์ว่า hello.rs
fn main() {
println!("Hello World!");
}
จากนั้น Compile เพื่อให้ได้ binary file เพื่อ execute มันได้
rustc hello.rs
จะได้ไฟล์ Output ชื่อเดียวกับไฟล์ คือ hello
บน Windows คือ hello.exe
จากนั้นลอง execute มันดู
./hello
Hello World!
หาก Compile ไม่ผ่าน จะมี Error บอก (ลองลบ
!
ออกเหลือแค่println
ดูครับ)
error[E0423]: expected function, found macro `println`
--> hello.rs:2:5
|
2 | println("Hello World");
| ^^^^^^^ not a function
|
help: use `!` to invoke the macro
|
2 | println!("Hello World");
| +
error: aborting due to previous error
จะเห็นได้ว่า Compile error message ก็มีประโยชน์มากๆ ทำให้เรารู้ว่า มันมีปัญหาอะไร บรรทัดไหน (สำหรับมือใหม่ ที่ไม่เคยเขียนโปรแกรม อาจจะกลัวๆ การอ่าน error message ลองพยายามอ่าน และทำความเข้าใจดูนะครับ ไม่ยาก)
Cargo เบื้องต้น
หลังจากลอง โปรแกรมแรกไปละ คราวนี้มาลองสร้างโปรเจ็คด้วยการใช้ Cargo
บ้าง
การสร้างโปรเจ็คใหม่ ใช้คำสั่ง cargo new <NAME>
เช่น
cargo new hello-rust
# จะได้ผลลัพธ์
Created binary (application) `hello-rust` package
ตัว Cargo จะทำการสร้างโฟลเดอร์ hello-rust
ขึ้นมา พร้อมกับไฟล์ src/main.rs
และ Cargo.toml
ดังนี้
.
├── Cargo.toml
└── src
└── main.rs
Cargo.toml
- เป็นเหมือน metadata ของโปรเจ็คเรา (เรียกว่า manifest) รู้ว่าใช้ library อะไรบ้าง หากใครเขียน Node.js มาก่อน ก็เหมือนกับpackage.json
ครับsrc/main.rs
- ไฟล์หลัก จะเห็นว่า เหมือนกับเราสร้างไฟล์ปกติเลย
ตัวอย่างข้างใน Cargo.toml
จะเห็นว่ามี name
มี version
มี editor
และส่วน dependencies
[package]
name = "hello-rust"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ทีนี้เวลา compile เราไม่ต้องใช้ rustc
แล้ว เราใช้คำสั่ง cargo run
ครับ (จริงๆ มันใช้ rustc
นั่นแหละ แต่ Cargo รันให้เรา)
cargo run
จะได้ผลลัพธ์ประมาณนี้
Compiling hello-rust v0.1.0 (/Users/chai/dev/hello-rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.27s
Running `target/debug/hello-rust`
Hello, world!
ไฟล์จะถูก compile ไว้ที๋โฟลเดอร์ target
เราลอง execute ตัว binary ไฟล์ดูได้
./target/debug/hello-rust
# ผลลัพธ์
Hello, world!
ใช้คำสั่ง cargo build
เพื่อ compile และ build package
cargo build
ข้อแตกต่างระหว่าง cargo build
และ cargo run
คือ
cargo run
จะ compile ถ้ายังไม่ถูก compile และ run โปรแกรมcargo build
จะ compile และ build เฉยๆ ไม่ได้รันโปรแกรม
หากอยากลบไฟล์ต่างๆ พวก binary ที่ compiled ไว้ ก็สามารถลบได้ด้วยคำสั่ง
cargo clean
การติดตั้ง Dependencies เช่น ติดตั้ง rand
ที่เป็น random generator บน crates.io ก็เพิ่มไปในไฟล์ Cargo.toml
ได้เลย
[dependencies]
rand = "0.8.5"
เวลา build
มันก็จะไปทำการดาวน์โหลด library มาติดตั้ง ก่อน compile ครับ
สุดท้าย Build ที่เราเห็น จะสังเกตเห็นว่า มัน unoptimized
เนื่องจากว่ามัน compile และ build binary ที่มีพวก debugging information หรืออะไรเต็มไปหมด ถ้าเราอยาก optimized / production ก็ใช้ --release
:
cargo build --release
Compiling hello-rust v0.1.0 (/Users/chai/dev/hello-rust)
Finished release [optimized] target(s) in 0.11s
สำหรับ Cargo ก็มีหนังสือนะครับ ไปอ่านเพิ่มเติมได้ครับ The Cargo Book
Rust แบบรวบรัด สำหรับคนมีพื้นฐานภาษาอื่นๆ
- การประกาศตัวแปร ใช้
let
ชื่อตัวแปรจะใช้แบบsnake_case
- มีการใช้
const
เวลาประกาศค่าคงที่ - ปิด statment ด้วย semicolon
- ฟังค์ชั่น ใช้ keyword
fn
ดังที่เห็นตอน Hello World แรก println!
เป็น marco ที่เอาไว้แสดงค่า
fn main() {
let number = 99;
let second_variable = 999;
let mut a_number = 1;
println!("second_variable is {}", second_variable);
a_number = 2;
println!("a_number is {}", a_number);
}
ผลลัพธ์
second_variable is 999
a_number is 2
ประกาศตัวแปร แบบกำหนด type รองรับ type ต่างๆ เช่น i8
, i16
, i32
, i64
, i128
และ unsigned integer
let x:i32 = 1;
let y:u32 = 14;
Float ตัว compiler จะใช้ f64
นอกจากจะกำหนด type ให้มัน
let thailand = 3.0;
let thailand_f: f32 = 4.0;
Boolean true
กับ false
let is_odd = 2 % 2 == 0;
println!("2 is odd? {}", is_odd);
Character และ String
// char
let i_am_a = 'a';
// string literal
let s: &str = "Hello World!";
// string allocated memory
let hello: &'static str = "hello";
// ใช้ String::new()
let mut string = String::new();
string.push('H');
// Heap
let greeting = String::from("Hello World");
If/Else ก็เหมือนภาษาอื่นๆ
let score = 81;
if score > 49 {
println!("Passed!");
} else {
println!("F!");
}
Loop
for i in 0..10 {
println!("{}", i);
}
let mut i = 0;
while i < 10 {
println!("hello");
i = i + 1;
}
Array ข้อมูลที่เก็บใน collection ต้องเป็น type เดียวกันและมีขนาดแน่นอน ตัวอย่าง กำหนด type และขนาด array:
let nums: [i32; 3] = [1, 2, 3];
Tuple เหมือนกับ Array ต่างกันที่ค่าข้างใน collection ต่างชนิดกันได้
let my_tuple = ('A', 10, true);
Struct คล้ายๆ tuple ข้างในมี fields ที่ต่าง type กันได้
// Struct แบบมี fields
struct Worker {
name: String,
department: String,
remote: bool
}
// Struct แบบ Unit struct
struct Unit;
// Struct แบบ มีแต่ type (Tuple struct)
struct OnlyYou(char, bool);
รองรับ Enum เหมือนภาษาอื่นๆ
enum Keyboard {
KEYUP,
KEYDOWN
}
Trait เหมือน Interface
trait Frobnicate<T> {
fn frobnicate(self) -> Option<T>;
}
กำหนด function รับค่า return ค่า
fn sum(a: u32, b: u32) -> u32 {
return a + b;
}
fn main() {
let result = sum(10, 20);
println!("10+20={}", result);
}
การ return ค่า ตอนจบ function จะใช้บรรทัดสุดท้าย (โดยไม่ต้องใส่ semicolon)
fn sum(a: u32, b: u32) -> u32 {
a + b
}
// มีค่าเท่ากัน
fn sum(a: u32, b: u32) -> u32 {
return a + b;
}
คร่าวๆ ก็มีประมาณนี้ สำหรับ Rust บทความแรก ก็ขอจบเพียงเท่านี้ก่อนครับ ส่วนตัวผมไม่กล้าแนะนำไปมากกว่านี้ เพราะยังไม่ชำนาญเท่าไหร่ กลัวจะสร้างความเข้าใจผิด 😅 แนะนำอ่านเพิ่มเติมครับ และหากใครมีอะไรแนะนำ ข้อเสนอแนะ มาพูดคุยกันได้นะครับ
- Rustling และ Rust Book เหมาะสำหรับอ่านคู่กันมากครับ ( ตอนนี้ผมก็กำลังหัดอยู่ตรงนี้ครับ วนๆ บทที่ 1-10 หลายรอบมาก)
- Tour of Rust - สามารถเข้าไปลองอ่าน ทำความเข้าใจได้ครับ
- Rust by Example - คล้ายๆ Rust Book อ่านเพิ่มเติม ต่อยอดได้ครับ
- Easy Rust - ผมชอบเล่มนี้ อ่านง่าย และเข้าใจง่ายดี (อ่านไปนิดเดียว)
- Rust Learning - รวม links & resources ต่างๆ น่าจะมีครบหมด อยู่ที่ตัวเราแล้วแหละ
สรุป
หวังว่าบทความนี้จะเป็นประโยชน์ และเป็นแนวทาง หรือแรงบันดาลใจให้ใครหลายๆ คนที่กำลังสนใจ Rust มาลองหัดเขียน กันดูนะครับ แล้วมาเรียนไปพร้อมๆกันครับ
Happy Coding ❤️
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit