콘텐츠로 이동

Rust 배열

배열(array)은 모두 같은 타입인 값들을 담는, 크기가 고정된 목록이에요. 핵심은 “크기가 고정”이라는 점이에요. 배열은 한 번 만들면 늘리거나 줄일 수 없어요. 크기가 바뀌는 목록이 필요하다면 벡터를 쓰면 돼요.

fn main() {
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
println!("{:?}", numbers);
}

[i32; 5] 타입은 “i32 값 5개짜리 배열”이라고 읽어요. 길이도 타입의 일부예요. 그래서 [i32; 5]와 [i32; 3]은 서로 다른 타입으로 취급돼요.

▶ 직접 실행해 보기

타입은 Rust가 추론하게 두고 값만 적어도 돼요.

let numbers = [1, 2, 3, 4, 5];

배열을 같은 값 N개로 채우려면 이렇게 줄여 써요.

fn main() {
let zeros = [0; 5]; // [0, 0, 0, 0, 0]
println!("{:?}", zeros);
}
▶ 직접 실행해 보기

배열의 인덱스는 0부터 시작하고, 대괄호를 써요.

fn main() {
let fruits = ["사과", "바나나", "체리"];
println!("{}", fruits[0]); // 사과
println!("{}", fruits[2]); // 체리
println!("길이: {}", fruits.len());
}
▶ 직접 실행해 보기

범위를 벗어난 접근은 잡아내요

섹션 제목: “범위를 벗어난 접근은 잡아내요”

존재하지 않는 인덱스에 접근하려고 하면, Rust는 엉뚱한 메모리를 몰래 읽는 대신 프로그램을 멈춰요.

fn get_fruit(fruits: [&str; 3], index: usize) -> &str {
fruits[index]
}
fn main() {
let fruits = ["사과", "바나나", "체리"];
println!("{}", get_fruit(fruits, 10)); // 실행 중에 패닉이 일어나요
}
thread 'main' (12345) panicked at src/main.rs:2:5:
index out of bounds: the len is 3 but the index is 10

이 메시지는 Rust가 영어로 출력해요. “인덱스가 범위를 벗어났어요. 길이는 3인데 인덱스는 10이에요”라는 뜻이고, src/main.rs:2:5는 패닉이 일어난 위치(2번째 줄, 5번째 칸)예요.

fn main() {
let numbers = [10, 20, 30];
for n in numbers {
println!("{n}");
}
}
▶ 직접 실행해 보기

배열은 다른 배열을 담을 수 있어요. 그러면 게임판이나 작은 스프레드시트처럼 행과 열이 있는 격자가 돼요. 아래 grid의 타입은 [[i32; 3]; 2]이고, “각각 i32 값 3개짜리 배열인 행이 2개”라고 읽어요.

fn main() {
// 2행 3열
let grid = [
[1, 2, 3],
[4, 5, 6],
];
println!("1행 2열: {}", grid[1][2]);
let mut total = 0;
for row in grid {
println!("{:?}", row);
for value in row {
total += value;
}
}
println!("합계: {total}");
}

실행 결과:

1행 2열: 6
[1, 2, 3]
[4, 5, 6]
합계: 21
▶ 직접 실행해 보기

grid[1][2]는 “1행, 그리고 그 행 안의 2열”이라는 뜻이에요. 둘 다 0부터 세기 때문에 두 번째 행의 세 번째 값이에요. 모든 값을 방문하려면 행을 도는 반복문 하나와, 그 안에서 각 행의 값을 도는 반복문 하나를 써요.

모든 행의 길이는 같아야 해요. 행의 길이가 타입의 일부이기 때문이에요. 순회하면서 각 위치도 필요하다면 .iter().enumerate()로 인덱스와 값을 함께 얻을 수 있어요. for 반복문 페이지에 나와 있어요.

크기가 고정되어 있고 미리 알 수 있을 때(예를 들어 일주일의 7일) 배열을 쓰세요. 항목을 추가하거나 빼야 할 때는 Vec을 쓰세요. 실제로는 대부분이 이 경우예요. 일상적인 Rust 코드에서 배열은 벡터보다 덜 쓰여요.

배열 [4, 8, 15, 16, 23, 42]를 만드세요. 모든 값을 더한 다음, 합계와 소수점 두 자리까지의 평균을 출력해 보세요. 힌트: for로 돌면서 total에 계속 더하고, 나누기 전에 두 숫자를 as로 f64로 바꾸세요.

정답 보기
fn main() {
let numbers = [4, 8, 15, 16, 23, 42];
let mut total = 0;
for n in numbers {
total += n;
}
let average = total as f64 / numbers.len() as f64;
println!("합계: {total}");
println!("평균: {average:.2}");
}

실행 결과:

합계: 108
평균: 18.00
▶ 직접 실행해 보기

as f64가 없으면 total / numbers.len()은 정수 나눗셈이 돼요. 게다가 total(i32)과 len()(usize)의 타입이 달라서 Rust가 에러를 내요.

일주일 동안의 기온 [18, 25, 12, 31, 22, 27, 19]가 있어요. 가장 높은 기온을 찾아서 출력해 보세요. 힌트: let mut hottest = temps[0];으로 시작한 다음, 반복하면서 더 큰 값을 찾을 때마다 바꿔 넣으세요.

정답 보기
fn main() {
let temps = [18, 25, 12, 31, 22, 27, 19];
let mut hottest = temps[0];
for t in temps {
if t > hottest {
hottest = t;
}
}
println!("가장 더운 날의 기온: {hottest}");
}

실행 결과:

가장 더운 날의 기온: 31
▶ 직접 실행해 보기

0이 아니라 temps[0]에서 시작하는 게 중요해요. 모든 기온이 영하라면 0에서 시작했을 때 틀린 답이 나오거든요.

  • 배열은 고정된 길이를 가지고, 그 길이는 타입의 일부예요: [i32; 5].
  • 요소에는 array[index]로 접근하고, 인덱스는 0부터 시작해요.
  • 범위를 벗어난 접근은 정의되지 않은 동작 대신 실행 중 패닉을 일으켜요.
  • 배열은 배열을 담을 수 있어요: [[i32; 3]; 2]는 grid[행][열]로 읽는 격자예요.
  • 크기를 바꿔야 한다면 Vec을 쓰세요.

이해도 점검

1. Rust 배열의 길이에 대해 맞는 설명은 무엇일까요?

2. 실행 중에 범위를 벗어난 배열 인덱스에 접근하면 어떻게 될까요?

3. let zeros = [0; 5];는 무엇을 만들까요?

점수: 0 / 3