สรุป The Rust Programming Language ฉบับมือเก่า ตอนที่ 5

Kasama Chenkaow
2 min readDec 7, 2024

--

บทความนี้สรุปจากหนังสือ The Rust Programming Language chapter 5 ด้วยความคิดเห็นของผมเอง อาจมีการตีความที่มีโอกาสผิดพลาดได้ ทางที่ดีถ้าอยากได้ reference จริงๆแนะนำต้นทางครับ

(Link ตอนที่แล้ว)

บทนี้ ตัว Struct เองเป็นหนทางนึงในการ group พวก values ต่างๆเข้าด้วยกันเพื่อให้เกิด meaning ที่เราต้องการ ซึ่งถ้าเป็นมือเก่าก็น่าจะคุ้นๆมาจากภาษาอื่นมาพอสมควร

ตัวอย่าง struct

struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}

บทนี้พอจะ skimming ได้เยอะอยู่ แต่มี notable points อยู่นิดหน่อยที่ผมพอจะคิดได้

  • Struct update -> เราสามารถสร้าง struct ใหม่จากของเก่าได้ด้วยโค้ดประมาณนี้
    let user2 = User {
email: String::from("another@example.com"),
..user1
};

แต่ที่ต้องระวังคือถ้าบาง fields ถูกย้าย ownership จะทำให้ทั้ง instance (ในกรณีนี้นี้ user1) จะไม่ valid ไปเลย

(จริงๆ ทางหนังสือบอกว่าสามารถประกาศ field ของ struct แบบ email: &str เพื่อรับค่าเป็น reference แทน แต่ปัญหาคือเราต้องกำหนด lifetime ให้กับมัน ซึ่งเค้ายังไม่เฉลย บอกว่าจะบอกให้บทที่ 10)

  • Tuple structs ผมคิดว่าคือ Named Tuples
  • Unit-Like Structs -> Empty Structs, อันนี้เหมือนจะเอาไปใช้ทีหลังเรื่อง traits
  • Debug trait -> ตัวนี้เหมือนเป็นของแถมว่าเราสามารถติด trait Debug ให้กับ struct ได้เพื่อให้มันสามารถถูก displayed ผ่าน println!() ได้

ยกตัวอย่างโค้ดด้านล่างนี้

#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};

println!("rect1 is {rect1:?}");
}

แบบนี้ก็จะ print rect1 is Rectagle { width: 30, height: 50 } ออกมาทาง stdout ให้เลยโดยที่เราไม่ต้องไป implement Display trait เอง

  • ของแถมอีกอันที่ผมคิดว่าน่าสนใจมากก็คือ dbg! ที่ทำให้เราสามารถ debug แบบ inline ได้เลย แถมไม่ต้องห่วงเรื่อง ownership ด้วยเพราะตัว function คือ ownership ให้เสมอ

ยกตัวอย่างเช่นโค้ดนี้

    let rect1 = Rectangle {
width: dbg!(30 * scale),
height: 50,
};

ก็จะ print output ด้านล่างเข้าไปที่ stderr

`[src/main.rs:10:16] 30 * scale = 60`

  • อีกหนึ่ง feature ของ Struct ก็คือเราสามารถ associate functions ให้กับมันได้แบบนี้
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}

ตัว &self ก็จะแทน reference ของ instance ที่ call function นี้ โดยถ้า function รับ self เข้ามาแบบนี้จะเรียกว่า method (และสามารถรับเป็นทั้ง self &self หรือ &mut self ก็ได้)

ส่วนถ้า associated function ไม่ได้รับ self เข้ามาก็จะไม่ใช่ method เช่น

impl Rectangle {
fn new(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}

ก็จะถูกเรียกได้แบบนี้ Rectangle::new(10) เป็นต้น

พอมานั่งคิดๆดู เวลาเรา associate functions ให้กับ Struct ได้แบบนี้ concept มันคล้ายกับ Class ใน OOP พอสมควรเลย แต่ผมอาจจะยังอ่านไม่ถึงเรื่องลึกๆ มันคงต้องมีเหตุผลแหล่ะที่เค้าไม่ได้เรียกมันว่า Class

จบละ บทนี้มือเก่าน่าจะอ่านเร็วพอสมควรเพราะไม่ได้ต่างอะไรมากมายกับ concepts ในภาษาอื่นๆ แค่ต้องคอยคิดเรื่อง Ownership กับเรียกรู้ syntax ใหม่นิดหน่อย!

--

--

No responses yet