트랙
/
Cairo
Cairo
/
연습 문제
/
수습 마법사
수습 마법사

수습 마법사

학습 연습 문제

소개

배열

Cairo 코어 라이브러리는 Array 타입을 구현해요.

다른 프로그래밍 언어에서 흔히 볼 수 있는 배열 타입과 비슷하지만, 몇 가지 중요한 차이점이 있어요:

  • 원소는 Array 타입의 뒤쪽에만 효율적으로 추가할 수 있고, 앞쪽에서만 효율적으로 제거할 수 있어요.
  • 배열 인덱스를 사용해 항목을 직접 설정할 수는 없어요.

배열은 ArrayTrait::new 함수로도, array! 매크로로도 만들 수 있어요:

let empty: Array<u32> = ArrayTrait::new();
let one_to_four = array![1, 2, 3, 4];

ArrayTrait::append 함수를 사용하면 배열에 원소를 추가할 수 있어요:

let mut num_array = array![1, 2, 3, 4];
num_array.append(5);
// -> [1, 2, 3, 4, 5]

ArrayTrait::pop_front 함수를 사용하면 배열에서 원소를 제거할 수 있어요:

let mut one_to_four = array![1, 2, 3, 4];

one_to_four.pop_front();
// -> [2, 3, 4]

Cairo는 Array의 "스냅샷"처럼 동작하는 Span 타입도 도입했어요.

모든 Array는 ToSpanTrait::span 함수로 Span으로 변환할 수 있어요:

let one_to_four = array![1, 2, 3, 4];
let one_to_four_span = one_to_four.span();
// -> [1, 2, 3, 4]

배열을 Span으로 변환하는 것은 매우 효율적이에요. Span은 Cairo가 배열의 일부를 "바라볼" 수 있게 해 주는 자료 구조일 뿐이고, 배열을 어떤 식으로도 수정하지 않거든요.

배열을 Span으로 변환하면, Array에서 직접 허용되는 것보다 더 많은 연산을 할 수 있어요. 예를 들어 span의 앞쪽에서 항목을 제거하는 것 같은 연산이에요.

let one_to_four = array![1, 2, 3, 4];
let mut one_to_four_span = one_to_four.span();
one_to_four_span.pop_back();
// -> [2, 3, 4]

pop_back을 호출하려면 mut 키워드로 one_to_four_span을 변경 가능하게 만들어야 한다는 점에 유의해요. pop_back은 span이 "바라보는" 배열의 구간을 줄여서 span을 변경하거든요.

지침

마술사가 되려는 Elyse는 기초를 좀 연습할 필요가 있어요.

Elyse에게는 조작하고 싶은 카드 더미가 있어요.

조금 더 쉽게 하려고 1부터 10까지의 카드만 사용해요.

카드 더미는 Array로 표현하는데, 더미의 맨 아래가 배열의 앞쪽에, 더미의 맨 위가 배열의 뒤쪽에 와요.

1. 더미의 맨 위에 카드를 넣기

insert_top 함수를 구현해요. 이 함수는 주어진 새 카드를 더미의 맨 위에 추가한 더미의 복사본을 반환해요.

let stack = array![5, 9, 7, 1];
insert_top(stack, 8);
// -> [5, 9, 7, 1, 8]

2. 더미에서 맨 위 카드 빼기

remove_top_card 함수를 구현해요. 이 함수는 맨 위 카드를 뺀 더미의 복사본을 반환해요.

주어진 더미가 비어 있으면, 원래 더미를 그대로 반환해야 해요.

let stack = array![3, 2, 6, 4, 8];
remove_top_card(stack);
// -> [3, 2, 6, 4]

3. 더미의 맨 아래에 카드를 넣기

insert_bottom 함수를 구현해요. 이 함수는 주어진 새 카드를 더미의 맨 아래에 추가한 더미의 복사본을 반환해요.

let stack = array![5, 9, 7, 1];
insert_bottom(stack, 8);
// -> [8, 5, 9, 7, 1]

4. 더미의 맨 아래에서 카드 빼기

remove_bottom_card 함수를 구현해요. 이 함수는 맨 아래 카드를 뺀 더미의 복사본을 반환해요.

주어진 더미가 비어 있으면, 원래 더미를 그대로 반환해야 해요.

let stack = array![8, 5, 9, 7, 1];
remove_bottom_card(stack);
// -> [5, 9, 7, 1]

5. 더미의 크기 확인하기

check_size_of_stack 함수를 구현해요. 이 함수는 더미의 크기가 주어진 stack_size와 같은지 확인해요.

let stack = array![3, 2, 6, 4, 8];
check_size_of_stack(stack, 4);
// -> false

Cairo에서 배열을 다루는 일이 다른 프로그래밍 언어에서만큼 간단하지 않은 이유를 이해하려면, Cairo가 불변 메모리 모델을 사용한다는 점을 기억해 두면 도움이 돼요. 불변 메모리 모델이란 메모리 셀에 한 번 값이 쓰이면 다시 덮어쓸 수 없고, 오직 읽기만 할 수 있다는 뜻이에요.

Cairo는 이 특징을 어느 정도 감춰 주기 때문에, 개발자는 변수를 마치 변경할 수 있는 것처럼 선언하고 사용할 수 있어요.

덕분에 코드를 작성하는 일, 특히 Array 타입(내부적으로는 "바이트의 배열"인 ByteArray도 포함해요)을 사용하는 코드를 작성하는 일은 조금 더 어려워지지만, 신뢰할 수 없는 기계에서도 자신 있게 실행할 수 있는 증명 가능한 프로그램을 작성할 수 있게 해줘요. 그래서 이런 트레이드오프는 충분히 가치가 있어요.

GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Cairo Exercism

수습 마법사 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Cairo 트랙을 개념 25개연습 문제 68개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.