Tour of Rust - Ch.4 - Generic Types
เขียนวันที่ : Apr 24, 2022
บันทึกการเรียน Tour Of Rust บทเรียนที่ 4 - Tour of Rust - Chapter 4 - Generic Types
Generic เป็น type ที่มีความสำคัญมากในภาษา Rust สามารถใช้แทนที่ค่า null ได้, การจัดการกับ Error case และ Collections
Chapter 4 - Generic Types 🦀
What Are Generic Types?
- คือการกำหนด
struct
หรือenum
แค่บางส่วน และที่เหลือให้ compiler จัดการ - คือ Type ที่เรากำหนดขึ้นมาเองได้ ตอน compile-time
- ใช้ keyword
::<T>
- หรือที่เรียกกันว่าturbofish
ตัวอย่าง generic types
struct BagOfHolding<T> {
item: T,
}
- จะเห็นว่าเรากำหนด type เป็น
T
type อะไรก็ได้ และเวลาเราใช้ ขึ้นอยู่กับว่าตอนเราใช้ เรากำหนดให้T
เป็น types อะไร แบบนี้:
let i32_bag = BagOfHolding::<i32> { item: 42 };
let bool_bag = BagOfHolding::<bool> { item: true };
Representing Nothing
- ภาษาอื่นๆ เราใช้ค่า
null
ได้ แต่ใน Rust ไม่มีค่าnull
- แต่มี
None
ให้ใช้นั่นเอง จะเห็นบ่อยๆ กับการใช้ร่วมกับOption
Option
เอาไว้ใช้กับค่าที่อาจจะเป็นnull
ก็ได้ โดยที่เราไม่ต้องใช้null
ตัวภาษษ Rust มี generic enum ที่ชื่อ Option
แบบนี้
enum Option<T> {
None,
Some(T),
}
เวลาที่เราสร้าง struct type แบบด้านล่าง ตัว item
เราเลยเป็นได้ทั้ง None
หรือ Some
struct BagOfHolding<T> {
item: Option<T>,
}
// เป็น None
let i32_bag = BagOfHolding::<i32> { item: None };
// เป็น Some
let i32_bag = BagOfHolding::<i32> { item: Some(42) };
Result
- คล้ายๆ
Option
ตัวResult
ก็เป็น Generic type อีกตัวในภาษา Rust ส่วนใหญ่จะเอาไว้ handle Result, Error มีรูปแบบนี้
enum Result<T, E> {
Ok(T),
Err(E),
}
- สังเกตว่า generic types ด้านบน มีทั้ง
T
และE
เวลาเราใช้งานจะใช้แบบนี้
fn do_something_that_might_fail(i:i32) -> Result<f32,String> {
if i == 42 {
Ok(13.0)
} else {
Err(String::from("this is not the right number"))
}
}
- จากโค๊ดด้านบน
T
คือ typef32
จะส่งผลลัพธ์Ok(f32)
ตอน success - และ
E
คือ typeString
จะส่งErr(String)
กลับไปตอน error - ตัวฟังค์ชั่น
main
ก็สามารถคืนค่าResult
ได้เหมือนกัน
fn main() -> Result<(), String> {
// code.
//
// ใช้ unit value เพื่อบอกว่า Result Ok
Ok(())
}
Graceful Error Handling
- เราจะเห็น
Result
ใช้ร่วมกับ?
บ่อยๆ ซึ่งโค๊ดด้านล่าง
do_something_that_might_fail()?
มีค่าเท่ากับการใช้ Ok
และ Err
แบบนี้
match do_something_that_might_fail() {
Ok(v) => v,
Err(e) => return Err(e),
}
ตัวโค๊ดก็จะสั้นลง เพราะเหมือน ?
เป็นการรวม result Ok
และจะ failed ถ้ามี Err
fn main() -> Result<(), String> {
// Look at how much code we saved!
let v = do_something_that_might_fail(42)?;
println!("found {}", v);
Ok(())
}
Ugly Option/Result Handling
- มาดูการใช้ function ที่ชื่อว่า
unwrap
ที่มีในOption
และResult
- ตัว
unwrap
จะทำการดึงค่าOption
หรือResult
ออกมา ถ้าเจอค่า enumNone
หรือErr
จะpanic!
ตัวอย่างโค๊ดจากเว็บ ที่เกิดการ panic
fn do_something_that_might_fail(i: i32) -> Result<f32, String> {
if i == 42 {
Ok(13.0)
} else {
Err(String::from("this is not the right number"))
}
}
fn main() -> Result<(), String> {
// concise but assumptive and gets ugly fast
let v = do_something_that_might_fail(42).unwrap();
println!("found {}", v);
// this will panic!
let v = do_something_that_might_fail(1).unwrap();
println!("found {}", v);
Ok(())
}
เวลา compile จะได้ result ประมาณนี้
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "this is not the right number"', src/main.rs:15:45
Vectors
- เป็น generic type ที่มีประโยชน์ที่สุดอีกตัวนึง และน่าจะใช้บ่อยมากๆ เพราะถ้าจะสร้าง collection ก็มักใช้ vector
- การสร้าง vector จะใช้ macro
vec!
- ตัว
Vec
จะมี methoditer()
ที่ทำให้เราสามารถ loop ได้ Vec
เป็นแค่ struct โดยเก็บ reference ไปยัง list ใน heap
ตัวอย่างสร้าง vector ด้วย type i32
let mut i32_vec = Vec::<i32>::new(); // turbofish <3
i32_vec.push(1);
i32_vec.push(2);
i32_vec.push(3);
สามารถสร้าง Vector แบบไม่ต้อง explicit type ก็ได้ ตัว Rust จะรู้เอง
let mut float_vec = Vec::new();
float_vec.push(1.3);
float_vec.push(2.3);
float_vec.push(3.4);
สร้างแบบ macro vec!
let string_vec = vec![String::from("Hello"), String::from("World")];
let i32_vec = vec![1, 2, 3];
// ใช้ .iter() เพื่อ loop
for word in string_vec.iter() {
println!("{}", word);
}
สรุปบทที่ 4
บทนี้ได้เรียนรู้เรื่อง Generic type จริงๆ ถ้าเขียนภาษาอื่นๆ ที่เป็น Statically Typed ก็น่าจะเข้าใจไม่ยากครับ ว่า Generic type คืออะไร แต่อาจจะงงๆ นิดๆเกี่ยวกับพวก Result
, Option
, None
พวกนี้ แต่ถ้าเขียนบ่อยๆ ยังไงก็ต้องใช้แน่นอน
อ่านเพิ่มเติม