Tour of Rust - Ch.3 - Basic Data Structure Types

Published on

เขียนวันที่ : April 16, 2022

tour-of-rust/chapter3

บันทึกการเรียน Tour Of Rust บทเรียนที่ 3 - Tour of Rust - Chapter 3 - Basic Data Structure Types

Chapter 3 - Basic Data Structure Types 🦀

Struct

  • struct เป็น Collection หรือกลุ่มของข้อมูล
struct Monster {
    name: String,
    age: i32,
    arms: i32,
    legs: i32,
    weapon: String
}

Calling Methods

  • methods คล้ายๆกับ functions (ที่ใช้ fn) แต่ต่างกันตรง methods นั้น define ใน context ของ struct
  • จริงๆแล้ว methods ก็คือ functions ที่ทำใน struct (อาจจะฟังดูสับสน เหมือนหรือไม่เหมือนกันแน่? ดูตัวอย่างครับ)
  • static methods - คือเมธอดที่เป็นของชนิดตัวแปร เรียกด้วย :: เช่น String::from()
  • instance methods - คือเมธอดที่เป็นของตัวแปร ใช้ . เช่น s.len()

เอาจริงๆ ผมก็เพิ่งรู้นะเนี่ย ผมไปเรียกมันเป็น function ตลอด และบางทีก็เรียกสลับกันด้วยทั้ง function/method และเพิ่งเห็นใน doc ก็ใช้ methods

fn main() {
    // Using a static method to create an instance of String
    let s = String::from("Hello world!");
    // Using a method on the instance
    println!("{} is {} characters long.", s, s.len());
}
// Declare a struct:
struct Student {
    id: i32,
    name: String
}

// Declare its method:
impl Student {
    fn some_method() {}
}

Memory

  • data memory - สำหรับเก็บข้อมูลที่รู้ขนาด (กำหนดขนาดไว้ชัดเจนแล้ว) รวมถึงค่าคงที่ต่างๆ
  • stack memory - สำหรับข้อมูลที่ถูก declare ใน function โดยตำแหน่งของข้อมูลจะไม่เปลี่ยนแปลงตลอดการทำงานของ function.
  • heap memory - ข้อมูลที่ถูกสร้างขึ้นในขณะ application ทำงาน เช่น เพิ่ม ลบ ปรับขนาด - ส่วนนี้ข้อมูลจะช้าเพราะด้วยความที่มัน dynamic เปลี่ยนแปลงได้ - เมื่อข้อมูลเพิ่มเข้ามาใน heap เราเรียกว่า allocation และข้อมูลถูกลบ เราเรียก deallocation

Create data in memory

  • เวลาสร้าง instance ของ Struct ตัวโปรแกรมจะสร้างข้อมูลใน memory
Structname {...}
  • การเข้าถึง field ของ Struct ใช้ dot operator (.)
  • พวกข้อมูลที่เป็น read-only จะไปอยู่ใน data memory
struct SeaCreature {
    animal_type: String,
    name: String,
    arms: i32,
    legs: i32,
    weapon: String,
}

fn main() {
    // SeaCreature's data is on stack
    let ferris = SeaCreature {
        // String struct is also on stack,
        // but holds a reference to data on heap
        animal_type: String::from("crab"),
        name: String::from("Ferris"),
        arms: 2,
        legs: 4,
        weapon: String::from("claw"),
    };

    let sarah = SeaCreature {
        animal_type: String::from("octopus"),
        name: String::from("Sarah"),
        arms: 8,
        legs: 0,
        weapon: String::from("none"),
    };

    println!(
        "{} is a {}. They have {} arms, {} legs, and a {} weapon",
        ferris.name, ferris.animal_type, ferris.arms, ferris.legs, ferris.weapon
    );
    println!(
        "{} is a {}. They have {} arms, and {} legs. They have no weapon..",
        sarah.name, sarah.animal_type, sarah.arms, sarah.legs
    );
}
  • String::from เพื่อสรา้ง field struct แบบ String ซึ่งค่านี้สามารถเปลี่ยนแปลงได้ โดย:
  1. ไปสร้างเป็น heap memory สำหรับข้อความที่ต้องการแก้ไข
  2. จับเก็บเป็น reference ที่อ้างอถึงตำแหน่ง heap memory และเซฟใน String struct.
  • สุดท้าย ตอน struct ถูกสร้างเสร็จ ทั้ง ferris และ sarah จะถูกกำหนด location แน่นอนในโปรแกรม ถูกเก็บไว้ใน stack

Tuple-like Strcuts

  • คือ Struct ที่หน้าตาเหมือน tuple
struct Location(i32, i32);

fn main() {
    // This is still a struct on a stack
    let loc = Location(42, 32);
    println!("{}, {}", loc.0, loc.1);
}

Unit-like Structs

  • นอกจาก tuple เรายังสามารถสร้าง Struct ได้แบบ Unit (คือ tuple ว่างๆ ())
  • ซึ่ง Struct แบบนี้ถูกใช้น้อยมากๆ
struct Marker;

fn main() {
    let _m = Marker;
}

Enumerations

  • Enumerations คือให้เราสร้าง type ใหม่ให้มีขุดข้อมูล กลุ่มข้อมูลที่เราต้องการ ใช้ keyword enum
enum Keyboard {
    UP,
    DOWN,
    LEFT,
    RIGHT
}
  • match เป็นตัวช่วยจัดการ condition ของ enum เช่น
#![allow(dead_code)] // this line prevents compiler warnings

enum Species {
    Crab,
    Octopus,
    Fish,
    Clam
}

struct SeaCreature {
    species: Species,
    name: String,
    arms: i32,
    legs: i32,
    weapon: String,
}

fn main() {
    let ferris = SeaCreature {
        species: Species::Crab,
        name: String::from("Ferris"),
        arms: 2,
        legs: 4,
        weapon: String::from("claw"),
    };

    match ferris.species {
        Species::Crab => println!("{} is a crab",ferris.name),
        Species::Octopus => println!("{} is a octopus",ferris.name),
        Species::Fish => println!("{} is a fish",ferris.name),
        Species::Clam => println!("{} is a clam",ferris.name),
    }
}

Enumerations with Data

  • element ของ enum สามารถเป็นได้ทั้ง data type เดียว หรือมีหลาย data type ก็ได้
  • เมื่อใช้ match มาจับคู่ของ enum เราสามารถผูกตัวแปรให้ value ได้เลย
  • enum หลายๆคนรู้จักในชื่อ tagged union
  • algebraic types หมายถึงการเอา type หลายๆตัวมารวมกันเป็น type ใหม่
enum Species { Crab, Octopus, Fish, Clam }
enum PoisonType { Acidic, Painful, Lethal }
enum Size { Big, Small }
enum Weapon {
    Claw(i32, Size),
    Poison(PoisonType),
    None
}
  • ดู enum Weapon ข้างในเป็น data type คนละชนิด

สรุปบทที่ 3

บทนี้มีทฤษฎีพวก memory มาเกี่ยวข้อง ซึ่งถ้าอ่านเพิ่มเติม และเข้าในว่า ข้อมูลแต่ละชนิดเก็บลง memory แบบใดบ้าง จะทำให้เราเข้าใจการทำงาน รวมถึงจัดการกับ ตัวแปร, reference ได้ดีขึ้น (ส่วนตัวผมก็ยังมีปัญหาตรงนี้เยอะมากๆ และก็พยายามอ่านพวกนี้เรื่อยๆ)

ส่วนเรื่อง Enum และ Match ใช้บ่อยๆ จนชอบ และก็สนุก และมีประโยชน์มากๆ

อ่านเพิ่มเติม

Discord