Slices
Slice คืออะไร?
หัวข้อที่มีชื่อว่า “Slice คืออะไร?”slice คือ reference ไปยังลำดับของ element ที่ต่อเนื่องกันใน collection ไม่ได้เป็นเจ้าของข้อมูล — เป็นการ borrow view เข้าไปยังหน่วยความจำที่มีอยู่แล้ว
slice มีสอง type ที่พบบ่อย:
&[T]— slice ของ array หรือ vector ใด ๆ ของ typeT&str— string slice; view เข้าไปยังข้อมูล string แบบ UTF-8
เพราะ slice เป็น reference เสมอ lifetime ของ slice จึงผูกอยู่กับ collection ที่ borrow มา
Slice ของ Array และ Vector
หัวข้อที่มีชื่อว่า “Slice ของ Array และ Vector”เมื่อมี array หรือ vector คุณสร้าง slice ได้โดยใช้ range syntax ภายในวงเล็บเหลี่ยม:
fn main() { let numbers = [10, 20, 30, 40, 50];
let all: &[i32] = &numbers[..]; // entire array let first_three: &[i32] = &numbers[..3]; // indices 0, 1, 2 let middle: &[i32] = &numbers[1..4]; // indices 1, 2, 3 let last_two: &[i32] = &numbers[3..];// indices 3, 4
println!("all: {:?}", all); println!("first three: {:?}", first_three); println!("middle: {:?}", middle); println!("last two: {:?}", last_two);}สรุป range syntax:
| Syntax | ความหมาย |
|---|---|
[..] | ทั้ง collection |
[..n] | n element แรก (index 0 ถึง n-1) |
[m..n] | index m ถึง n-1 |
[m..] | จาก index m ไปจนสุดท้าย |
String Slices (&str)
หัวข้อที่มีชื่อว่า “String Slices (&str)”string slice (&str) คือ reference ไปยังบางส่วนของ String หรือ string literal ตัว string literal เองก็เป็น &str — เป็น slice ของข้อมูลแบบ read-only ที่ฝังอยู่ใน binary
fn main() { let s = String::from("hello world");
let hello: &str = &s[..5]; // "hello" let world: &str = &s[6..]; // "world"
println!("{} {}", hello, world);
// A string literal is already &str let literal: &str = "Rust is fast"; println!("{}", literal);}Slice ป้องกัน Dangling Index
หัวข้อที่มีชื่อว่า “Slice ป้องกัน Dangling Index”หากไม่มี slice คุณอาจเก็บ index เข้าไปใน string แล้วแก้ไข string นั้น — ทำให้ index ชี้ไปยังข้อมูลที่ไม่มีความหมาย ด้วย string slice borrow checker จะรับประกันว่า slice ไม่สามารถมีอายุยืนกว่าข้อมูลที่อ้างถึงได้
fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { if byte == b' ' { return &s[..i]; // slice up to the space } } s // whole string is one word}
fn main() { let sentence = String::from("hello world"); let word = first_word(&sentence); // sentence cannot be mutated while word (a slice of it) is alive println!("first word: {}", word);}Slice ในฐานะพารามิเตอร์ของฟังก์ชัน
หัวข้อที่มีชื่อว่า “Slice ในฐานะพารามิเตอร์ของฟังก์ชัน”ฟังก์ชันที่ทำงานกับลำดับข้อมูลควรรับ slice แทนที่จะเป็น type ที่เป็นเจ้าของค่า วิธีนี้ทำให้ฟังก์ชันทำงานได้กับ array, vector และบางส่วนของทั้งสองอย่างโดยไม่ต้องขอ ownership
- ควรเลือกใช้
&[T]แทน&Vec<T>สำหรับพารามิเตอร์ที่เป็นลำดับข้อมูล - ควรเลือกใช้
&strแทน&Stringสำหรับพารามิเตอร์ที่เป็น string
ทั้ง &Vec<T> และ &String จะ coerce ไปเป็น slice ที่เทียบเท่ากันโดยอัตโนมัติ ณ จุดที่เรียก
fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { if byte == b' ' { return &s[..i]; } } s}
fn sum_slice(nums: &[i32]) -> i32 { let mut total = 0; for &n in nums { total += n; } total}
fn main() { // String slice let sentence = String::from("hello world"); let word = first_word(&sentence); println!("first word: {}", word);
// Integer slice let numbers = [10, 20, 30, 40, 50]; let middle: &[i32] = &numbers[1..4]; println!("middle slice: {:?}", middle); println!("sum of middle: {}", sum_slice(middle));
// String slice literal let greeting: &str = "Rust is safe"; println!("slice: {}", &greeting[..4]);}Compiling…