소개
아주 작은 예제에서는 변수를 따로 사용해도 괜찮지만, 실제 프로그램에서는 관련 데이터를 하나로 묶은 값이 필요한 경우가 많습니다. Rust의 struct는 이러한 레코드의 형태를 정의하고, impl 블록은 해당 레코드에 속하는 작업을 제공합니다.
이 실습에서는 네 가지 간단한 수정으로 준비된 InventoryItem 모델을 완성합니다. 필드를 정의하고, 유효한 항목을 생성하고, &self를 통해 재고 가치를 계산하고, &mut self를 통해 수량을 업데이트합니다. 마지막 프로그램은 저장된 상태와 메서드의 동작을 모두 확인합니다.
Inventory 레코드 정의
이 단계에서는 재고 항목 하나에 속하는 세 가지 데이터를 정의합니다.
준비된 Cargo 프로젝트로 이동한 다음 소스 파일을 엽니다.
cd /home/labex/project/inventory-item
nano src/main.rs
struct InventoryItem { ... } 선언은 새로운 레코드 타입을 만듭니다. 중괄호 안에서 각 필드는 이름 뒤에 콜론과 타입을 적습니다. 모든 InventoryItem 값은 이 필드를 모두 제공해야 합니다.
Step 1 주석을 다음 세 필드로 바꿉니다.
name: String,
price_cents: u32,
quantity: u32,
name은 텍스트의 소유권을 가지며, 두 u32 필드는 음수가 아닌 정수를 저장합니다. 뒤에 붙은 쉼표는 필드를 구분하고, 나중에 줄을 쉽게 추가하거나 순서를 바꿀 수 있게 합니다.
Ctrl+O를 눌러 저장하고 Enter를 누른 다음 Ctrl+X로 종료합니다. Cargo를 사용해 타입 정의를 확인합니다.
cargo check
경고 없이 Finished 결과가 나오면 struct의 형태가 올바르고 준비된 각 값이 명확하게 사용된다는 뜻입니다. 생성자에는 아직 완성되지 않은 코드를 표시하는 임시 표식인 todo!가 있습니다. Rust는 cargo check 중에는 이를 허용하지만, todo!에 도달하는 경로를 실행하면 패닉으로 중단됩니다. 다음 단계에서 프로그램을 실행하기 전에 이를 교체합니다.
완전한 항목 생성
이 단계에서는 new 연관 함수를 완전한 InventoryItem을 반환하는 생성자로 바꿉니다.
impl InventoryItem 블록은 해당 타입과 관련된 작업을 묶습니다. new는 self를 받지 않으므로 연관 함수이며, InventoryItem::new(...)처럼 타입을 통해 호출합니다. value_cents와 같은 메서드는 self를 받고 item.value_cents()처럼 값에서 호출합니다. 반환 타입 Self는 이 impl 블록 안에서 InventoryItem을 가리키는 다른 이름입니다.
소스 파일을 엽니다.
nano src/main.rs
new 안에서 todo!(...) 줄 전체를 다음 코드로 바꿉니다.
Self { name, price_cents, quantity }
이 코드는 struct 표현식입니다. Rust의 필드 축약 문법에서는 매개 변수와 필드의 이름이 같을 때 name을 name: name으로 작성할 수 있습니다. 이 표현식은 함수가 반환할 값을 나타내므로 뒤에 세미콜론을 붙이지 않습니다.
저장하고 종료한 다음 프로그램을 확인하고 실행합니다.
cargo check
cargo run --quiet
현재 출력은 다음과 같아야 합니다.
Preparing Notebook at 250 cents with 4 units
Item: Notebook
Unit price: 250 cents
Starting value: 0 cents
Adding 3 units
Quantity after restock: 4
Final value: 0 cents
이제 항목이 전달된 필드 값과 함께 생성되었습니다. 값이 0으로 표시되고 수량이 바뀌지 않는 것은 나머지 두 메서드에 아직 자리 표시자가 남아 있기 때문이며, 이 단계에서는 정상입니다.
&self로 값 계산
이 단계에서는 항목의 소유권을 가져오거나 항목을 변경하지 않고 두 필드를 읽는 메서드를 완성합니다.
&self 매개 변수는 현재 InventoryItem에 대한 공유 참조입니다. 이는 구체적인 타입이 &InventoryItem인 빌린 값을 간단히 표현한 것입니다. item.value_cents()를 호출하면 메서드가 이 값을 자동으로 받습니다.
소스 파일을 엽니다.
nano src/main.rs
value_cents 안에서 0 자리 표시자만 다음 코드로 바꿉니다.
self.price_cents * self.quantity
점 표기법으로 빌린 항목의 필드를 선택합니다. 곱셈 결과는 센트 단위의 전체 값이 되며, 뒤에 세미콜론이 없으므로 이 표현식이 메서드가 반환하는 u32 값이 됩니다.
저장하고 종료한 다음 실행합니다.
cargo run --quiet
이제 값 관련 줄은 다음과 같아야 합니다.
Starting value: 1000 cents
...
Final value: 1000 cents
250센트인 상품 4개의 값은 1000센트입니다. 아직 restock이 수량을 변경하지 않았으므로 두 줄의 값이 여전히 같습니다. 마지막 단계에서 이 변경 작업을 완성합니다.
&mut self로 재입고
이 단계에서는 독점적인 빌림 접근을 통해 한 필드를 변경하는 메서드를 완성합니다.
리시버 &mut self는 현재 항목에 대한 변경 가능한 참조입니다. 이를 사용하면 소유권을 가져오지 않고 메서드 안에서 필드를 업데이트할 수 있습니다. main의 바인딩은 이미 let mut item으로 선언되어 있으므로, 이 임시 변경 가능 접근을 제공할 수 있습니다.
소스 파일을 엽니다.
nano src/main.rs
restock 안의 Step 4 주석을 다음 코드로 바꿉니다.
self.quantity += amount;
+= 연산자는 오른쪽 값을 기존 필드에 더한 뒤 그 결과를 해당 필드에 다시 저장합니다. 이 코드는 문장이므로 세미콜론으로 끝납니다.
저장하고 종료한 다음 완성된 모델을 확인하고 실행합니다.
cargo check
cargo run --quiet
전체 출력은 다음과 같아야 합니다.
Preparing Notebook at 250 cents with 4 units
Item: Notebook
Unit price: 250 cents
Starting value: 1000 cents
Adding 3 units
Quantity after restock: 7
Final value: 1750 cents
수량이 4에서 7로 바뀌고, 같은 value_cents 메서드가 변경된 상태를 확인합니다. restock이 끝나면 변경 가능한 빌림도 종료되므로, 이후 코드에서는 항목을 일반적으로 읽을 수 있습니다.
요약
관련 필드를 하나로 묶는 struct를 정의하고, Self 생성자를 통해 값을 만들고, &self 메서드로 상태를 읽고, &mut self 메서드로 상태를 업데이트했습니다. 최종 재고 출력으로 생성, 계산, 변경이 함께 올바르게 작동한다는 것을 확인했습니다.


