배열과 슬라이스

배열은 동일한 자료형(T)의 모음으로, 연속된 메모리에 저장됩니다. 대괄호 [] 로 정의하고, 길이는 [T; length] 로 컴파일 할 때 지정해야합니다.

슬라이스는 배열과 비슷한 개념이지만, 컴파일 할 때 길이를 지정하지 않는 점이 다릅니다. 대신, 객체 내부에 2개의 워드를 가집니다. 첫번째 워드는 데이터를 가리키는 포인터로 사용하고, 두번째 워드에는 슬라이스의 길이를 저장합니다. 워드는 usize와 크기가 같은데, 이 값은 CPU 에따라 달라집니다. 즉 x86-64 CPU에서는 64비트가 됩니다. 배열의 일부를 빌려올 때 사용할 수 있고, 문법은 &[T] 입니다.

use std::mem;

// 이 함수는 슬라이스의 소유권을 빌려옵니다.
fn analyze_slice(slice: &[i32]) {
    println!("전달된 슬라이스의 첫 요소는 {}입니다.", slice[0]);
    println!("전달된 슬라이스는 {}개의 요소를 가지고 있습니다.", slice.len());
}

fn main() {
    // 길이가 고정된 배열 (배열에서 지정했으므로, 추가로 자료형을 지정하지 않아도 됩니다)
    let xs: [i32; 5] = [1, 2, 3, 4, 5];

    // 모든 요소들을 같은 값으로 초기화할 수 있습니다.
    let ys: [i32; 500] = [0; 500];

    // 인덱스는 0 부터 시작합니다.
    println!("배열의 첫번째 요소: {}", xs[0]);
    println!("배열의 두번째 요소: {}", xs[1]);

    // 배열에 들어있는 요소의 갯수는 `len` 으로 알 수 있습니다.
    println!("배열의 요소의 갯수: {}", xs.len());

    // 배열은 스택에 할당됩니다.
    println!("배열에는 {} 바이트가 할당되어 있습니다.", mem::size_of_val(&xs));

    // 배열은 자동으로 슬라이스 형태로 빌릴 수 있습니다.
    println!("배열 전체를 슬라이스로 빌립니다.");
    analyze_slice(&xs);

    // 슬라이스느 배열의 특정 부분을 지정할 수 있습니다.
    // 문법은 [starting_index..ending_index] 입니다.
    // starting_index 는 슬라이스의 처음을 나타내고
    // ending_index 는 슬라이스의 마지막 위치를 나타냅니다.
    println!("배열의 일부를 슬라이스로 빌립니다");
    analyze_slice(&ys[1 .. 4]);

    // 아래 문장에서는 index out of bounds 오류가 발생합니다.
    println!("{}", xs[5]);
}