이 코드에서 &s1을 사용하는 이유와 함수 내의 동작 방식을 이해하려면 "참조자(Reference)"와 "소유권(Ownership)"이라는 두 가지 개념을 살펴보는 것이 중요합니다.
소유권(Ownership)
Rust에서는 메모리 안전성을 보장하기 위해 각 데이터는 소유자(Owner)가 존재합니다.
예를 들어, let s1 = String::from("hello");에서는 s1이 "hello"라는 String 데이터의 소유자가 됩니다.
참조자(Reference)
참조자는 &를 사용하여 데이터의 소유권을 빼앗지 않고 데이터에 접근할 수 있도록 합니다. 즉, 소유권을 넘겨주지 않고도 다른 곳에서 데이터를 사용할 수 있게 해줍니다.
&s1은 s1 값을 읽을 수 있게 하지만, s1의 소유권을 빼앗지 않습니다.다음 코드를 한 줄씩 분석해 보겠습니다.
let s1 = String::from("hello");
"hello"라는 String 데이터를 생성하고, 이 데이터의 소유권을 s1이 가집니다.let len = calculate_length(&s1);
&s1은 s1 값을 참조하는 참조자(Reference)를 생성합니다.calculate_length 함수가 데이터를 사용할 수 있게 하면서도 s1이 여전히 "hello"의 소유권을 유지합니다.fn calculate_length(s: &String) -> usize { // s는 String의 참조자입니다
s.len()
}
s는 &String 타입입니다. 이는 이 함수가 String 데이터를 소유하지 않으며, 단지 참조만 한다는 것을 의미합니다.s.len()은 참조자를 통해 데이터의 길이를 계산하고 반환합니다.s는 스코프를 벗어나지만, 이는 참조자일 뿐 데이터의 소유권을 가지고 있지 않기 때문에 메모리를 해제하지 않습니다.s1)는 여전히 유효합니다.s1)의 소유권이 calculate_length로 이동하며, 이후에는 s1을 사용할 수 없게 됩니다.fn calculate_length(s: String) -> usize { // s는 String을 소유합니다
s.len()
}
let s1 = String::from("hello");
let len = calculate_length(s1);
// 이제 s1은 더 이상 유효하지 않습니다.
s1의 소유권이 함수로 이동하므로 s1은 더 이상 유효하지 않게 됩니다.s1의 데이터를 소유하고 처리하는 대신 참조자를 사용하여 소유권을 유지하도록 설계된 원리와 대비됩니다.&s1은 s1의 값을 소유권을 넘기지 않고 읽기 위해 사용됩니다.
이로 인해 함수 내부에서 데이터를 처리하면서도 원래 데이터는 그대로 유지할 수 있는 유연성을 제공합니다.