최근 Ruby와 Rails를 공부하고 있는데, Ruby의 Symbol이라는 게 잘 이해가 되지 않았다.
기존에 내가 배웠던 언어들 중에는 그와 비슷한게 없었던 터라 도무지 감이 안 잡혔다.
구글링 결과 대략 감을 잡았으니, Ruby Symbol의 정체에 대해 간단히 정리해본다.
위의 두 문장 모두 'hello'라는 문자열을 출력한다. 이런 이유로 Symbol을 String의 오리타입(duck type) 클래스로 오해하기도 한다. 하지만, 아래 코드를 보면 알겠지만, Symbol은 절대로 String이 아니다.
Symbol이 String의 사촌 쯤으로 오해받는 것은 Symbol을 immutable string 용도로 많이 사용하기 때문이다. 나처럼 Lisp 언어에 대한 경험이 없는 사람이라면, 대충 예제코드들을 보면서 그렇게 생각할 가능성이 매우 높다.
Java등의 언어에서는 String이 immutable Class이므로 Hash의 키로 사용했을 경우 그다지 문제될 것이 없지만, Ruby에서는 String이 mutable class이므로 Hash의 키로 쓰일 때, 키로 쓰인 객체의 값이 변경될 경우 rehash 메소드를 호출해줘야 하는 경우가 생긴다. 따라서 Ruby에서는 가능하면 Hash의 키로 String대신 Symbol을 쓰는 것을 선호한다. 그러니 나 같은 놈은 처음부터 Symbol = Immutable String 으로 이해하고는 그 뒤부터는 미궁으로 빠져버린다.
Symbol을 그 정의대로 '이름을 가진, 그리고 그 이름에 대해서 유니크(unique)한 객체'이다. String이 따옴표로 둘러쌓인 문자열로 표기되듯이, Symbol은 :name의 형태로 표기되며, name이 문자열로 표기될 수 있지만 그 자체는 String이 아닌 Symbol객체이다. 그리고 아래 코드에서 보여지듯이, 특정 이름을 갖는 Symbol 객체는 유일하다.
Ruby의 String이 mutable 객체이므로, 성능상의 이유로 Symbol이 immutable string의 대체물로 사용되곤 하지만, Symbol은 garbage collect가 되지 않으므로 자칫하면 메모리 누수가 발생할 수 있음을 유의해야 한다. 대충 아래와 같은 용도로 사용하는 것이 추천된다.
기존에 내가 배웠던 언어들 중에는 그와 비슷한게 없었던 터라 도무지 감이 안 잡혔다.
구글링 결과 대략 감을 잡았으니, Ruby Symbol의 정체에 대해 간단히 정리해본다.
String vs. Symbol
puts :hello #symbol
puts "hello" #string
위의 두 문장 모두 'hello'라는 문자열을 출력한다. 이런 이유로 Symbol을 String의 오리타입(duck type) 클래스로 오해하기도 한다. 하지만, 아래 코드를 보면 알겠지만, Symbol은 절대로 String이 아니다.
puts :hello.size # NoMethodError
puts :hello[0,2] # NoMethodError
puts "hello".size #5
puts "hello"[0,2] # "he"
Symbol이 String의 사촌 쯤으로 오해받는 것은 Symbol을 immutable string 용도로 많이 사용하기 때문이다. 나처럼 Lisp 언어에 대한 경험이 없는 사람이라면, 대충 예제코드들을 보면서 그렇게 생각할 가능성이 매우 높다.
Java등의 언어에서는 String이 immutable Class이므로 Hash의 키로 사용했을 경우 그다지 문제될 것이 없지만, Ruby에서는 String이 mutable class이므로 Hash의 키로 쓰일 때, 키로 쓰인 객체의 값이 변경될 경우 rehash 메소드를 호출해줘야 하는 경우가 생긴다. 따라서 Ruby에서는 가능하면 Hash의 키로 String대신 Symbol을 쓰는 것을 선호한다. 그러니 나 같은 놈은 처음부터 Symbol = Immutable String 으로 이해하고는 그 뒤부터는 미궁으로 빠져버린다.
Symbol을 그 정의대로 '이름을 가진, 그리고 그 이름에 대해서 유니크(unique)한 객체'이다. String이 따옴표로 둘러쌓인 문자열로 표기되듯이, Symbol은 :name의 형태로 표기되며, name이 문자열로 표기될 수 있지만 그 자체는 String이 아닌 Symbol객체이다. 그리고 아래 코드에서 보여지듯이, 특정 이름을 갖는 Symbol 객체는 유일하다.
puts :hello.class # Symbol
puts "hello".class # String
puts :hello.object_id == :hello.object_id # true
puts "hello".object_id == "hello".object_id #false
Symbol의 용도
그렇다면 Symbol은 언제 사용하는 것이 좋을까?Ruby의 String이 mutable 객체이므로, 성능상의 이유로 Symbol이 immutable string의 대체물로 사용되곤 하지만, Symbol은 garbage collect가 되지 않으므로 자칫하면 메모리 누수가 발생할 수 있음을 유의해야 한다. 대충 아래와 같은 용도로 사용하는 것이 추천된다.
- 메소드의 argument list에 옵션 키워드의 이름
link_to 'Show', :action=>'show', :id= product - C의 enum와 같은 값을 표현할 때
/* C code*/
enum BugStatus { OPEN, CLOSED };
BugStatus original_status = OPEN;BugStatus current_status = CLOSED;
# Ruby
original_status = :opencurrent_status = :closed - Hash의 키 이름
foo = {
:host => 'localhost',
:port => 80 }
foo = { # String을 사용한 경우, 속성-값의 관계가 덜 명확해 보인다.
'host' => 'localhost',
'port' => 80} Reference
- 13 Wasy of Looking at a Ruby Symbol
- Symbols are not immutable strings
- Using Symbols for wrong reason
- Understanding Ruby Symbols
댓글을 달아 주세요