
Rust를 공부하면서 주의깊게 공부해야 할 부분은 아무래도 Ownership, 그리고 String &str의 차이라고 판단하였다. 기본 개념을 꽉 잡고 들어가지 않는다면 나중에 흔들릴 수 있기 때문에, 햇갈리거나 중요하다고 판단한 부분들을 차례대로 정리해 나가보겠다. 특히 메모리 할당 부분을 생각하면서 진행해보겠다.
- 러스트에서, 각각의 값은 소유자 (owner) 가 정해져 있습니다.
- 한 값의 소유자는 동시에 여럿 존재할 수 없습니다.
- 소유자가 스코프 밖으로 벗어날 때, 값은 버려집니다 (dropped).
- 러스트는 변수가 스코프 밖으로 벗어나면 drop이라는 특별한 함수를 호출합니다
String)의 경우에는 아래와 같이, 대입을 한 경우 String Data(스택에 있는 데이터)가 복사되며, 힙 영역의 데이터는 복사되지 않는다. 메모리 안정성을 보장하기 위해서, 러스트는 s1이 더 이상 유효하지 않다고 판단하여, 소유권을 s2에게 넘긴다. let s1 = String::from("hello");
let s2 = s1; // 오류 발생
- "hello"라는 문자열 데이터가 힙에 저장됨.
s1변수가 생성됨.s1은 힙을 가리키는 포인터, 길이, 용량을 스택에 저장한다.s1이 스코프를 벗어나면 Drop 트레잇이 실행되어 힙 메모리가 해제됨.
이렇게 사용하는 이유는 무엇일까요? 간단합니다. 만약에 s2, s1이 대입 이후에도 소유권을 모두 가지고 있는 경우, 만약 스코프 밖으로 벗어날 때 각각 메모리를 해제하게 되면 중복 해제 (double free) 에러가 발생할 겁니다.
clone이라는 method를 사용할 수 있다. let s1 = String::from("hello");
let s2 = s1.clone();
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
// 여기서 s는 함수 내에서만 사용할 수 있는 변수명이며, &String은 이 변수가 가질 타입입
fn calculate_length(s: &String) -> usize {
s.len()
}

- "hello"라는 문자열 데이터가 힙에 저장된다
s1변수가 생성됨.s1은 힙을 가르키는 포인터, 길이, 용량을 스택에 저장한다.&s1이라는,s1값을 참조하지만, 해당 값을 소유하지 않는 참조자를 생성한다.calculate_length는,&String타입을 갖는 변수를s인자로 받는다.calculate_length가 인자로 받은 변수는 해당 값을 소유하지 않으므로,s가 사용되지 않더라도, 참조자가 가리킨 값인s1이 버려지지 않습니다.
이때,
&T가 원본 타입의 메서드를 그대로 사용할 수 있는데, Rust의 자동 역참조(auto deref) 기능 덕분에,&T는 원본 T의 메서드를 그대로 사용할 수 있습니다.
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
s는 dangle 함수 내에서 생성됐기 때문에, 함수가 끝날 때 할당 해제됩니다. 하지만 코드에서는 &s를 반환하려 했고, 이는 유효하지 않은 String을 가리키는 참조자를 반환하는 행위이기 때문에 에러가 발생합니다.아래 그림과 같이, &s가 참조하는 값인 s는
dangle()함수 스코프 밖에서 메모리에서 사라지므로, &s가 가리키는 값은 그대로 남아있는데, 해당 가리키는 값(주소)에 다른 개체가 할당받았을 경우, 모르는 메모리를 참조하게 될 가능성이 있기 때문에 이를 댕글링 포인터라고 한다.

fn no_dangle() -> String {
let s = String::from("hello");
s
}