오늘은 러스트에서 가장 중요하면서도 처음에는 조금 생소할 수 있는 **'소유권 넘겨주기와 돌려받기'**에 대해 알아볼 거예요. 어렵게 생각하지 마세요! 우리가 일상생활에서 물건을 주고받는 것과 똑같답니다.
---
러스트에는 **소유권(Ownership: 메모리를 관리할 권리)**이라는 특별한 규칙이 있어요. 아주 귀한 **'황금 열쇠'**가 하나 있다고 상상해 보세요. 이 열쇠는 세상에 단 하나뿐이라서, **한 번에 딱 한 사람만** 가질 수 있어요.
* 내가 열쇠를 가지고 있으면, 내가 주인이에요.
* 내가 친구에게 이 열쇠를 주면, 이제 친구가 주인이고 **나는 더 이상 열쇠를 쓸 수 없어요.**
이것이 러스트가 메모리를 안전하게 관리하는 핵심 방법이랍니다!
---
함수를 호출하면서 변수를 전달하는 것은, 내가 가진 황금 열쇠를 함수에게 **'주는 것'**과 같아요.
fn main() {
let s1 = String::from("hello"); // s1이 "hello"라는 열쇠를 가집니다.
take_ownership(s1); // s1의 소유권을 함수에게 넘겨줍니다 (이동: Move).
// println!("{}", s1); // 에러! 이제 s1은 열쇠가 없어서 사용할 수 없어요.
}
fn take_ownership(some_string: String) { // some_string이 열쇠를 받았습니다.
println!("{}", some_string); // 열쇠를 잘 사용하고...
} // 함수가 끝나면 열쇠는 사라집니다 (메모리 해제).
**용어 풀이:**
* **이동(Move):** 소유권이 한 변수에서 다른 변수(또는 함수)로 완전히 옮겨가는 것을 말해요.
---
함수에게 열쇠를 줬는데, 나중에 내가 다시 그 열쇠를 써야 한다면 어떻게 할까요? 함수가 일을 마친 뒤에 다시 나에게 **'돌려주면'** 됩니다!
fn main() {
let s1 = String::from("hello"); // s1이 열쇠를 가집니다.
let s2 = give_back(s1); // s1을 주고, 다시 s2로 돌려받습니다.
println!("{}", s2); // s2가 열쇠를 돌려받았으므로 사용 가능합니다!
}
fn give_back(some_string: String) -> String { // 열쇠를 받아서...
some_string // 다시 밖으로 던져서(반환: Return) 돌려줍니다!
}
가끔은 열쇠도 돌려받고, 함수가 계산한 결과값도 같이 받고 싶을 때가 있죠? 그럴 때는 **튜플(Tuple: 여러 값을 하나로 묶은 바구니)**을 사용하면 편리해요.
fn main() {
let s1 = String::from("hello"); // s1이 열쇠를 가집니다.
let (s2, len) = calculate_length(s1); // 열쇠(s2)와 길잇값(len)을 동시에 받습니다.
println!("'{}'의 길이는 {}입니다.", s2, len); // 둘 다 기분 좋게 사용!
}
fn calculate_length(s: String) -> (String, usize) { // 바구니에 담아서 보냅니다.
let length = s.len(); // 길이를 재고...
(s, length) // 열쇠와 길이를 함께 돌려줍니다.
}
--
처음에는 "내가 만든 변수를 왜 마음대로 못 쓰게 해?"라고 생각하실 수 있어요. 하지만 이건 러스트가 여러분의 프로그램이 갑자기 멈추거나 메모리가 새어나가는 사고를 막아주기 위해 **미리 챙겨주는 친절한 배려**랍니다. "준 것은 더 이상 내 것이 아니다!"라는 규칙만 기억하세요. 익숙해지면 그 어떤 언어보다 안전하고 튼튼한 코드를 만드실 수 있을 거예요.
| 45. 가변 참조의 규칙 (0) | 2026.09.23 |
|---|---|
| 44. 참조와 대여: 빌려 쓰기 (0) | 2026.09.14 |
| 42. 복사(Copy)와 클론(Clone) (0) | 2026.09.14 |
| 41. 이동(Move) 현상 이해하기 (0) | 2026.09.08 |
| 40. 변수 범위와 메모리 해제 (0) | 2026.09.08 |