จากบทความที่แล้ว Rust language: Data Types เราได้มีการพูดถึงตัวแปรแบบ array ที่มีข้อจำกัดในเรื่องของขนาดของ array ที่ถูก fixed size ไว้ ไม่สามารถเพิ่มหรือลดขนาดได้
หากเราต้องการเก็บข้อมูลแบบกลุ่มโดยที่ให้ตัวแปรนั้นสามารถขยายหรือลดขนาดได้ ให้เลือกใช้งาน vector แทนการใช้ array
ก่อนอื่น ต้องทำความเข้าใจกันก่อนว่า Vectors, String และ hash map นั้น ไม่ได้เป็น Data Type พื้นฐาน เหมือนบทความที่แล้ว
แต่มันจะอยู่ในกลุ่มของ standard library ที่ไว้สำหรับจัดการกับโครงสร้างข้อมูล (data structures) หรือเรียกอีกอย่างว่า Collections Data type อื่นๆ ส่วนใหญ่มีไว้เพื่อเก็บค่าแค่ค่าเดียว แต่ collection สามารถเก็บค่าไว้หลายค่าได้
โดย data collections เหล่านี้จะชี้ไปที่ๆ เก็บมันเอาใน heap (memory) ให้นึกถึง pointer ของภาษา c หรือ go ซึ่งมันทำให้เราสามารถเก็บและเข้าถึงข้อมูลได้โดยไม่จำเป็นต้องรู้จำนวนของข้อมูล
Vector
เริ่มต้นที่ หากเราต้องการสร้าง vector ใหม่ ที่ไม่มีการกำหนดค่าเริ่มต้นอะไรไว้ เราสามารถเรียกใช้งานผ่านคำสั่ง Vec::new
fn main() {
let v: Vec<i32> = Vec::new();
println!("The value of v is: {:?}", v);
}
new vector
หากต้องการกำหนดค่าเริ่มต้นด้วย
fn main() {
let v = vec![1, 2, 3];
println!("The value of v is: {:?}", v);
}
new vector with default
Updating a Vector
เมื่อเราต้องการที่จะเพิ่มข้อมูลเข้าไปยัง vector ที่สร้างไว้ เราจะใช้คำสั่ง push
อย่าลืมเพิ่ม mut
เพื่อบอก compiler ให้รู้ว่าตัวแปรนี้สามารถแก้ไขได้
fn main() {
let mut v: Vec<i32> = Vec::new();
println!("The value of v is: {:?}", v);
v1.push(5);
v1.push(6);
v1.push(7);
v1.push(8);
println!("The value of v is: {:?}", v);
}
update data in vector
จากโค๊ด สังเกตว่า ถ้าหากเราต้องการจะ print ตัวแปร vector ออกมาจะต้องใส่ {:?}
ไว้ด้วยเสมอ ตัวนี้เป็นเหมือนกับการ debug mode เพื่อเข้าถึงค่าของตัวแปลนั้น
Reading Elements of Vectors
การอ่านข้อมูลใน vector มี 2 วิธี ในการอ้างอิงค่าที่เก็บไว้ใน vector ผ่าน index หรือใช้ฟังก์ชั่น get
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {third}");
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {third}"),
None => println!("There is no third element."),
}
}
reading elements of vector
จากโค๊ด การเข้าถึงข้อมูลใน vector แบบ index ก็เหมือนกับภาษาอื่นๆ ที่ใช้ []
แต่ที่น่าสนใจเลย คือ การเข้าถึงข้อมูลใน vector แบบฟังก์ชั่น get
เมื่อเราใช้เมธอด get
โดยที่ส่ง index ผ่านเป็น argument เราจะได้รับ Option<&T>
ที่เราสามารถใช้ในการกับ match
ได้
Slice
Slice เป็น ประเภทข้อมูลที่ใช้ในการอ้างอิงถึง collection ที่เก็บข้อมูลไว้ โดย slice นั้นจะไม่สามารถแก้ไข element ใน slice ได้โดยตรง แต่มันจะใช้หน่วยความจำน้อยกว่าการเข้าถึง array หรือ vector โดยตรง ทำให้การเข้าถึงข้อมูลผ่าน slice จะทำงานได้เร็วกว่าการเข้าถึงโดยตรง
เนื่องจาก slice เป็นการ reference ข้อมูล เลยทำให้ตัวของมันจะไม่มีความเป็น ownership (ไว้ค่อยอธิบายเรื่อง ownership ในบทความต่อไป)
การสร้าง Slice:
- จาก array หรือ vector: ใช้
&
และindex range
- จาก string literal: ใช้
&str
- ถ้าต้องการเก็บค่าจาก slice อื่น: ให้ใช้
clone()
fn main() {
let my_array: [i32; 5] = [1, 2, 3, 4, 5];
let my_slice: &[i32] = &my_array[1..4];
println!("The slice is: {:?}", my_slice);
}
slice with index range
เราสามารถใช้ slice กับ string ได้ แต่จะไม่สามารถแก้ไขมันได้
fn main() {
let my_str: &str = "Hello, world!";
println!("The my_str is: {:?}", my_str);
}
slice with string literal
ถ้าหากต้องการเก็บค่าจาก slice อื่น ให้ใช้ clone()
fn main() {
let my_array: [i32; 5] = [1, 2, 3, 4, 5];
let my_slice: &[i32] = &my_array[1..4];
let my_slice2: &[i32] = my_slice.clone();
println!("The my_slice2 is: {:?}", my_slice2);
}
copy data from slice
ทั้งหมดที่อ่านมาเป็นเพียงแค่วิธีการใช้ง slice เบื้องต้น ซึ่งการใช้งานจริงๆ จำเป็นต้องทำความเข้าใจ และเลือกใช้งานให้เหมาะสม เพื่อช่วยในการบริหารจัดการ memory ของระบบที่เราเขียนมันขึ้นมา