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

Kasama Chenkaow
2 min read3 days ago

--

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

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

บทนี้จะพูดถึง collections 3 ตัวคือ Vector, Strings และ Hash Maps

Vector

Vector ถ้าให้อธิบายสั้นๆก็คงเป็น array ที่อยู่ใน heap แทนที่จะเป็น stack แล้ว powerful กว่าเพราะมาพร้อม feature ที่ครบเครื่องกว่า เช่น size สามารถเพิ่มลดได้ เป็นต้น (แต่ยังคงต้องเป็น collection of the same type เหมือนกัน)

มีประเด็นนิดหน่อยตรงการอ่านค่า

  • indexing เช่น arr[10] แบบนี้สามารถ panic ได้ถ้า out of bound
  • ใช้ arr.get(10) แบบนี้จะไม่ panic แต่จะ return Option<&T> มาแทน

มีอีกเรื่องนึงคือถึงจะบอกว่าทั้ง collection ต้องเก็บ type เดียวกัน แต่เราสามารถใช้ enum ที่มี variants หลายๆ types ได้ อารมณ์เหมือน vec<UnionType> โดยที่เจ้า UnionType ในทีนี้คือ enum

Strings

บทความนี้ตอนแรกผมคิดว่าจะไม่มีอะไรเลย แต่ก็กลับมีสิ่งที่น่าสนใจอยู่

  • behind the scenes at the core ทุก string คือ slices ที่เป็น fixed length UTF-8 encoded
  • Strings จริงๆข้างหลังก็คือ Vector ของ bytes ที่ wrap ตัว slices แล้วทำให้มัน growable, mutable, owned
  • ที่ต่างกับ Vector ทั่วๆไปคือไม่สามารถใช้ indexing ได้ (คือไม่สามารถ s[10] แบบนี้ได้) เหตุผลคือพอเป็น UTF-8 encoded แล้วบางทีจะมีตัวอักษรที่ต้องใช้ 2 bytes ในการ represent แต่ Rust ไม่ได้รู้ว่า user ต้องการให้ return byte หรือ character จาก indexing
  • ก็เลยต้องใช้ range expression มาช่วยบอกให้ชัดๆ เช่น &s[0..4] แบบนี้ก็จะได้ค่าไป 4 bytes ซึ่งถ้าเป็นภาษาที่ตัวอักษรนึงคือ 2 bytes ก็จะได้ไป 2 characters อะไรแบบนี้
  • แล้วถ้าเกิดเราใช้ &s[0..1] เพื่อให้ได้ effect เดียวกับ indexing &s[0] ในภาษาที่เป็นเป็น 2-byte จะเกิออะไรขึ้น คำตอบก็คือจะโดน panic ที่ runtime
  • ทางที่ดีใช้ .chars() หรือ .bytes() แล้ว iterate เอาเลย safe สุด
for c in "Зд".chars() {
println!("{c}");
}

for b in "Зд".bytes() {
println!("{b}");
}

Hash Maps

อันนี้โดย basic ทั่วๆไปก็คล้ายๆกับ implementation ในภาษาอื่นๆนั่นแหล่ะ แต่มีความน่าสนใจนิดหน่อย

  • map.get() จะ return Option<&Value> ซึ่งเป็น immutable reference ถ้าไม่อยากให้มี reference ของ value อยู่ใน scope ก็ให้ใช้ .copies() จะได้ Option<Value> แทน (เช่น map.get(&key).copies() )
  • Iterate over ง่ายๆ ด้วย for (key, value) in &map
  • Function insert takes ownership นะ เช่น map.insert(key, value); แบบนี้ตัวแปร key กับ value จะโดน take ownership ไปแล้วจะไม่ valid ใน scope หลังจากนั้นอีกแล้ว
  • Insert ด้วย key ซ้ำก็ overwrite ปกติตาม common sense
  • สามารถทำการ insert if not existได้ด้วย map.entry(key).or_insert(value)
  • upsert ก็ทำได้คล้ายๆกัน
     let count = map.entry(key).or_insert(0);
*count += 1;

อย่าง code ข้างต้นก็คือจะ default value เป็น 0 หรือใช้ value ที่มีอยู่แล้ว จากนั้น dereference มาเอาค่ามา update (dereference ผมขอรอให้หนังสืออธิบายในบทต่อๆไปละกัน)

เย้จบแล้วบทที่ 8

--

--

No responses yet