By Weerasak Chongnguluam

Learn Rust: Basic Vector


Vector

Rust มี Vector type สำหรับเก็บข้อมูล type เดียวกันหลาย ๆ ค่า (collection) แต่ต่างจาก array ตรงที่ Vector เป็นแบบ dynamic size สามารถเพิ่ม ลด ขนาดของข้อมูลได้ และสามารถเก็บข้อมูลได้หลาย ๆ ค่า โดยไม่ต้องระบุขนาดของข้อมูลล่วงหน้า

Create Vector

เราสามารถสร้าง vector ใหม่ได้โดยเรียก associated function new ของ Vec เช่น

    // Create Vector of i32 instance
    let v: Vec<i32> = Vec::new();
    println!("{:#?}", v);

จะเห็นว่า Vec มี generic type parameter ที่เราต้องระบุ type ของข้อมูลที่จะเก็บไว้ใน vector นั้น ๆ ในตัวอย่างนี้เรากำหนดให้เก็บข้อมูลเป็น i32

ถ้าเราต้องการกำหนดค่าเริ่มต้นให้กับ vector เราสามารถใช้ macro vec! ได้เช่น

    // Create and intialize with vec! macro
    let v = vec![1, 2, 3, 4];
    println!("{:#?}", v);

Add Element to Vector

เราสามารถเพิ่มข้อมูลเข้าไปใน vector ได้โดยใช้ method push เช่น

    // Create mut Vector then push value
    let mut v: Vec<i32> = Vec::new();
    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    let v = v;
    println!("{:#?}", v);

ซึ่งเราก็ต้องประกาศ vector เป็น mutable ก่อนเพื่อให้สามารถเพิ่มข้อมูลเข้าไปได้

Access Element of Vector

เราสามารถเข้าถึงข้อมูลใน vector ได้โดยใช้ index ของข้อมูล ซึ่ง index เริ่มที่ 0 เช่น

    // get value by index start with zero
    let one = v[0];
    let two = v[1];
    let three = v[2];
    let four = v[3];
    println!("{one}, {two}, {three}, {four}");

ถ้าเราใช้ index ที่เกินขนาดของ vector Rust จะ panic และจบการทำงานของโปรแกรม ดังนี้

    // panic if index out of bounds
    let five = v[4];

หรือเราจะใช้ method get ก็ได้เช่นกัน โดยที่ method get จะ return Option<&T> ซึ่งจะทำให้เราเช็คได้ว่า index ที่เราเรียกมีข้อมูลหรือไม่ ถ้ามีข้อมูลจะ return Some(&T) ถ้าไม่มีข้อมูลจะ return None ดังนี้

    // get with get method that return Option<&T>
    if let Some(five) = v.get(5) {
        println!("found {five}");
    } else {
        println!("not found");
    }

Iterate Over Vector

เนื่องจาก vector implements IntoIterator trait เราสามารถ loop ข้อมูลใน vector ได้โดยใช้ for .. in loop เช่น

    // loop with for iterate on T, so v is move and cannot use after that
    for i in v {
        println!("{i}");
    }

แต่การที่เราใช้ v ตรง ๆ Iterator ที่ได้มันจะ move ตัว vector ไปใช้ใน Iterator ด้วยทำให้เราไม่สามารถใช้ v ได้อีกหลังจาก loop เพราะ ownership ของ v ถูกเปลี่ยนไปให้ Iterator แล้ว

ถ้าเราต้องการใช้ v หลังจาก loop เราสามารถใช้ &v แทนได้เพื่อให้ Iterator ใช้ reference ของ v เป็นการ borrow แทน ดังนี้

     // loop with for iterate on &T, so v is move and cannot use after that
    for i in &v {
        println!("{i}");
    }

หรือถ้าเราอยากแก้ไขข้อมูลใน vector โดยใช้ loop เราสามารถใช้ &mut v แทนได้เพื่อให้ Iterator ใช้ mutable reference ของ v เป็นการ borrow แทน ดังนี้

    let mut v = vec![1, 2, 3, 4];
    // loop with for iterate on &mut T, so we can update element by using defer
    for i in &mut v {
        *i*=2; // double
    }
    println!("{:#?}", v);

Slice Vector

เราสามารถสร้าง slice ของ vector ได้โดยใช้ & หน้า vector และ .. ระหว่าง index ที่เราต้องการ slice เช่น

    let s = &v[..];
    println!("{:#?}", s);

    let s = &v[1..];
    println!("{:#?}", s);

    let s = &v[1..2];
    println!("{:#?}", s);

    let s = &v[..2];
    println!("{:#?}", s);

Deref to Slice of T

เนื่องจาก vector มี method deref ที่ return slice ของ T ทำให้เราสามารถเรียก method ของ slice ได้โดยตรง เช่นเรียก iter() แบบนี้

    let v = vec![1, 2, 3, 4];
    for i in v.iter() {
        println!("{i}");
    }

สามารถดู method อื่น ๆ ของ vector ได้จาก Rust API Documentation