We will find a way, we always have.

-interstellar

Programming Language/러스트

[Rust] 러스트의 꽃, 소유권

Redddy 2024. 11. 22. 22:28

 

러스트를 배우면서 가장 신기했던 부분은 바로 소유권이였다.

 

러스트 소유권에는 세가지 규칙을 따른다. 

  • 각각의 값은 소유자 (owner) 가 정해져 있다.
  • 한 값의 소유자는 동시에 여럿 존재할 수 없다.
  • 소유자가 스코프 밖으로 벗어날 때, 값은 버려진다 (dropped).

 

소유자 개념을 이해하기 위해 한가지 예시를 들어보겠다. 

 

 

위 코드는 "레디"라는 문자열 객체를 만든 다음 tmp라는 변수에 할당을 해준다음 name을 출력하는 코드이다. 

 

자바로 작성하면 아래와 같다. 

 

 

자바에서는 아무런 문제 없이 돌아가지만 이 코드가 러스트에선 에러가 발생한다. 

 

 

컴파일 에러가 발생하고 실행시키면 해결방법도 친절히 알려준다.

 

에러 발생 이유는 바로 소유권 때문이다. 

 

처음에는 name이 힙 메모리에 저장된 문자열 "레디"를 소유하게 된다. 그 다음 tmp = name을 실행하면, 소유권이 name에서 tmp로 이동하게 된다. 러스트는 기본적으로 값의 소유권을 이동하며, 이동 이후 원래 소유자는 더 이상 해당 값을 사용할 수 없다. 소유권이 이미 tmp로 이동했기 때문에, name은 더 이상 유효하지 않고 이 name을 사용하려 할 때 예외가 발생하는 것이다.

 

 

러스트의 String 저장 방식을 살펴봐보자.

String은 힙에 데이터를 저장하는 소유권이 있는 타입이다. 이를 관리하기 위해 String은 포인터, 길이, 용량 정보를 스택에 저장한다. 

 

  • 포인터(Pointer): 힙 메모리에서 실제 문자열 데이터를 가리킨다.
  • 길이(length): 문자열 데이터의 길이를 나타낸다.
  • 용량(capacity): 힙에 할당된 메모리의 크기를 나타낸다.

 

 

 

이 상태에서 tmp = name을 실행하면 아래 그림처럼 될 것이다.

 

 

위와 같은 경우는 한 값의 소유자가 둘 이상 있는 경우니 러스트에서는 처음 name의 소유권을 해제시킨다. 

 

 

이제 러스트의 소유권 개념에 대해 살짝 감이 잡혔을거라 믿는다. 

 

또 다른 예제를 가져와서 살펴봐보자.

 

 

위 코드는 파라미터로 받은 문자열을 출력하는 함수가 있고 그 함수를 두 번 호출한다. 위 코드도 에러가 발생하는데, 이유는 첫 번째 takes_ownership(name)을 호출할 때, name 변수의 소유권이 함수의 매개변수 val로 이동한다. 함수가 실행을 마치고 반환되더라도 val은 스코프를 벗어나기 때문에 메모리가 해제된다. 그래서 이제 name은 더 이상 유효하지 않는다. 두 번째 takes_ownership(name)을 호출하면 name은 첫 번째 호출에서 소유권을 잃었기 때문에 더 이상 사용할 수 없는 상태이다. 이 시점에서 "use of moved value" 에러가 발생한다.

 

컴파일 에러

 

소유권 때문에 문제가 발생한다는 건 이제 알았다. 그럼 어떻게 해결할 수 있을까.

참조(reference)를 사용하거나 값을 복사(clone)하여 사용한다면 문제를 소유권 걱정 없이 값을 사용할 수 있다. 

 

'&'를 사용하면 값을 빌려주기만 하고 소유권은 유지할 수 있다. 

 

 

.clone() 함수를 사용하여 값의 복사본을 생성하여 전달할 수도 있다.

 

 

 

러스트의 소유권 시스템은 메모리를 안전하게 관리하면서도 GC 없이 높은 성능과 제어권을 제공하기 위한 설계이다. 

 


참고

rust 공식 문서

 

What is Ownership? - The Rust Programming Language

Ownership is a set of rules that govern how a Rust program manages memory. All programs have to manage the way they use a computer’s memory while running. Some languages have garbage collection that regularly looks for no-longer-used memory as the progra

doc.rust-lang.org