[0]

프로그래밍 언어에서 null이 도입된 이후에, 이와 관련된 무수한 버그들이 발생하였다. 대표적으로 null pointer dereference가 있는데, 이는 디버깅도 굉장히 어렵다. Rust에서는 이러한 이유로 null을 도입하지 않는다. 대신에 Option<T>라는 enum을 제공한다.

 

[1]

Option<T>는 std::option에 다음과 같이 정의되어 있다.

enum Option<T> {
    Some(T),
    None,
}

여기서 Some(T)는 해당 값이 non-null일 경우, None은 null일 경우에 대응한다고 생각하면 된다. 따라서 다음과 같은 방식으로 사용할 수 있다.

fn add(num: Option<i32>) -> Option<i32> {
    match num {
        None => None,
        Some(i) => Some(i + 1),
    }
}

add()는 int형의 인자를 하나 받아 1을 더해주고 리턴하는 단순한 함수다. null로 구현되어 있는 언어에서 if문을 통해 num이 null인지 아닌지 확인하는 것처럼, Rust에서도 유사하게 match를 통해 Option<T>가 None인지 Some인지를 확인하고 해당하는 동작을 한다. 여기까지는 다른 언어들이랑 유사하게 보인다. 그렇다면 Rust에서 null대신 Option<T>로 구현한 이유는 무엇일까?

 

[2]

핵심은 바로 Option<T>와 T가 다른 타입이라는 것이다. null이 구현되어 있는 언어에서는, 오브젝트에 null이 들어가거나, 의미 있는 값이 들어가거나 같은 타입이다. 예를 들어 다음과 같은 c프로그램은 아무 문제없이 컴파일된다.

void * get_addr(){
	void * ptr = get_addr_from_somewhere();    //can be null!
	return ptr;
}

위의 코드에서, ptr에 의미 있는 주소 값이 저장되든 아니든, return은 같은 void * 타입으로 이루어진다. 따라서 get_addr()을 호출한 함수에서, null체크를 해주지 않는다면 null pointer dereference와 같은 메모리 취약점이 발생할 수 있다. 반면 Rust에서는 Option<T>와 T가 완전히 다른 타입이기 때문에, 타입을 맞추지 않는다면, 컴파일 타임에 에러가 발생하게 된다.

 

[3]

그럼 Option의 퍼포먼스 오버헤드는 어떨까? 어느 정도 예상 가능하다싶이, Rust 컴파일러가 Option을 포인터로 컴파일 타임에 변환하기 때문에 런타임 오버헤드는 사실상 0이라고 할 수 있다! 되도록 많은 체크와 작업들을 컴파일 타임에 하고, 런타임 오버헤드는 없도록 하는 Rust의 철학이 다시한번 반영되었다고 생각하면 된다. 

 

다만 메모리 오버헤드는 어느정도 발생한다. C의 union과 마찬가지로, 원소 중 가장 큰 type의 사이즈를 갖도록 구현되어 있기 때문이다.(Enum이 어느 타입을 가질지 알 수 없으므로, 원소 중 가장 큰 type의 사이즈에 맞출 수밖에 없다.) 따라서, 포인터의 사이즈(32비트면 4바이트, 64비트면 8바이트)보다 작은 타입의 경우에는 Option<T>에서 그만큼의 메모리 낭비가 발생한다. 예컨대 i32는 4바이트지만 Option<i32>는 8바이트와 같은 식으로. 하지만 null값을 가정하는 타입이 거의 레퍼런스임을 감안하면 크게 부담되는 오버헤드는 아니라고 할 수 있다.

 

 

[참고]

https://doc.rust-lang.org/book/

 

Defining an Enum - The Rust Programming Language

Let’s look at a situation we might want to express in code and see why enums are useful and more appropriate than structs in this case. Say we need to work with IP addresses. Currently, two major standards are used for IP addresses: version four and versio

doc.rust-lang.org

https://stackoverflow.com/questions/16504643/what-is-the-overhead-of-rusts-option-type

 

What is the overhead of Rust's Option type?

In Rust, references can never be null, so in case where you actually need null, such as a linked list, you use the Option type: struct Element { value: i32, next: Option<box<element&...< p=""> </box<element&...<>

stackoverflow.com

 

'Computer Science > Rust' 카테고리의 다른 글

Rust의 async/await와 Future  (0) 2020.07.21
Rust의 Copy trait와 Clone trait  (2) 2020.06.30
Rust의 스마트 포인터  (0) 2020.05.20
Rust의 lifetime parameter  (0) 2020.05.05
Rust의 Trait  (1) 2020.03.10

+ Recent posts