DaleSchool

여러 값 다루기: 튜플, 배열, 벡터

입문15분

학습 목표

  • 튜플로 다른 타입의 값을 묶을 수 있다
  • 배열로 같은 타입의 고정 길이 값을 저장할 수 있다
  • Vec으로 크기가 변하는 목록을 만들 수 있다
  • for로 벡터의 요소를 순회할 수 있다

동작하는 코드

아래 코드를 Rust Playground에서 실행해보세요!

fn main() {
    // 튜플: 다른 타입의 값을 묶을 수 있어요
    let person = ("민수", 25, true);
    println!("이름: {}", person.0);
    println!("나이: {}", person.1);

    // 배열: 같은 타입, 고정 크기
    let colors = ["빨강", "초록", "파랑"];
    println!("첫 번째 색: {}", colors[0]);

    // 벡터: 같은 타입, 크기가 변할 수 있음
    let mut fruits = vec!["사과", "바나나", "포도"];
    fruits.push("딸기");
    println!("과일 수: {}", fruits.len());

    for fruit in &fruits {
        println!("🍎 {fruit}");
    }
}

세 가지 모두 여러 값을 하나로 묶는 방법이에요. 각각 쓰임새가 달라요!

직접 수정하기

  1. fruitspush로 좋아하는 과일을 2개 더 추가해보세요.
  2. colors[5]처럼 존재하지 않는 인덱스에 접근하면 어떻게 될까요? 직접 실행해보세요.

"왜?" — 세 가지 컬렉션의 차이

튜플 (tuple)배열 (array)벡터 (Vec)
타입서로 다른 타입 OK같은 타입만같은 타입만
크기고정고정변경 가능
만드는 법(값1, 값2)[값1, 값2]vec![값1, 값2]
접근 방법.0, .1[인덱스][인덱스]
추가/삭제불가불가push(), pop()

언제 뭘 쓸지 헷갈리면 이렇게 생각하세요.

  • 튜플: 이름과 나이처럼 다른 종류의 값을 묶을 때
  • 배열: 크기가 절대 안 바뀌는 고정 목록 (요일, 색상 등)
  • 벡터: 나머지 거의 모든 경우! 실무에서 가장 많이 쓰여요
fn main() {
    let mut scores = vec![90, 85, 77, 92];

    // 요소 추가
    scores.push(88);

    // 마지막 요소 제거
    let last = scores.pop(); // Some(88)
    println!("꺼낸 값: {last:?}");

    // for로 순회
    for score in &scores {
        println!("점수: {score}");
    }

    println!("총 {}개의 점수", scores.len());
}

pop()의 결과가 Some(88)로 나오는 게 신기하죠? 이건 나중에 배울 Option 타입이에요. 지금은 "값이 있을 수도 없을 수도 있다"를 표현하는 거라고만 알아두세요.

심화 학습

구조 분해 — 튜플의 값을 한 번에 꺼내기

튜플에서 값을 꺼낼 때 .0, .1을 쓰는 것 말고도 구조 분해(destructuring) 라는 방법이 있어요.

fn main() {
    let person = ("민수", 25, true);

    // 구조 분해로 각 값에 이름 붙이기
    let (name, age, is_student) = person;
    println!("{name}님은 {age}살이에요");

    if is_student {
        println!("학생이에요!");
    }
}

.0, .1보다 훨씬 읽기 좋죠? 값에 의미 있는 이름을 붙일 수 있어서 코드가 깔끔해져요.

인덱스 범위 초과

배열이나 벡터에서 존재하지 않는 인덱스에 접근하면 프로그램이 패닉(panic) 을 일으켜요.

fn main() {
    let numbers = [1, 2, 3];
    println!("{}", numbers[10]); // 패닉!
}

에러 메시지:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 10'

해석: "배열 길이는 3인데 인덱스 10에 접근하려 했어요"라는 뜻이에요. 이건 컴파일 에러가 아니라 런타임 에러예요 — 프로그램이 실행되다가 멈추는 거예요. 인덱스가 범위 안에 있는지 항상 확인하세요!

Vec을 함수에 넘기면 생기는 일

fn print_scores(scores: Vec<i32>) {
    for s in scores {
        println!("{s}");
    }
}

fn main() {
    let scores = vec![90, 85, 77];
    print_scores(scores);
    println!("총 {}개의 점수", scores.len()); // 에러!
}

에러 메시지:

error[E0382]: borrow of moved value: `scores`

scores를 함수에 넘기고 나면 더 이상 사용할 수 없어요! 지금은 .clone()을 붙여서 복사본을 만들어 전달하면 돼요.

fn print_scores(scores: Vec<i32>) {
    for s in scores {
        println!("{s}");
    }
}

fn main() {
    let scores = vec![90, 85, 77];
    print_scores(scores.clone()); // 복사본을 전달!
    println!("총 {}개의 점수", scores.len()); // OK!
}

왜 이런 일이 생기는지는 나중에 자세히 알아볼게요. 지금은 .clone()이 복사본을 만든다고만 기억하세요!

  1. 좋아하는 음식 5개를 벡터에 저장하고, for로 번호와 함께 출력해보세요.
    • 힌트: 카운터 변수를 mut으로 만들어서 매 반복마다 1씩 증가시키세요.
    • 출력 예시: 1. 떡볶이, 2. 피자, ...
  2. 숫자 벡터 vec![10, 25, 30, 15, 40]에서 for로 순회하면서 30 이상인 값만 출력하는 프로그램을 작성해보세요.

아래 코드에서 colors.len()의 값은 무엇일까요?