본문 바로가기
Ruby on Rails

Ruby Symbol에 대해서

by 혜리루 2020. 10. 11.

1. 서론

처음 루비를 시작할 때 새로 접했던 개념중에 하나가 symbol입니다.

본격적으로 rails 개발을 하면서 hash를 생성할때나, parameter를 받을 때 등등 여러 가지 상황에 symbol을 자주 사용했는데요.

사실 symbol이 immutable 하다는 것 외에는 string과의 차이점을 잘 알지 못하고 그냥 쓰고 있었습니다.

그냥 상수 느낌으로? 사용했던 것 같아요. 이제라도 제대로 알고 쓰기 위해 symbol에 대해 이것저것 찾아보았습니다.

 

2. symbol이란

symbol이란 간단히 말하면 콜론(:)으로 시작하는 문자열입니다. string은 따옴표(",')로 감싸진 문자열이고요.

symbol 객체가 string와 다른점은 크게 두가지가 있습니다.

1) symbol은 immutable한 객체입니다.

프로그래밍의 세계에서 immutable 하다는 말은 변경할 수 없다는 말입니다. 한번 선언한 immutable 객체는 객체의 수명이 다할 때 까지 변경할 수 없습니다. symbol 또한 그렇고요.

irb(main):034:0> symbol = :haeree
=> :haeree
irb(main):035:0> symbol + :a
Traceback (most recent call last):
        2: from /Users/haeree/.rbenv/versions/2.5.0/bin/irb:11:in `<main>'
        1: from (irb):35
NoMethodError (undefined method `+' for :haeree:Symbol)

위 처럼 한번 선언한 symbol객체는 수정할 수 없습니다.

irb(main):036:0> string = 'haeree'
=> "haeree"
irb(main):037:0> string += 'a'
=> "haereea"

 

반면 mutable한 객체인 string은 위처럼 쉽게 수정이 가능합니다.

 

2)symbol은 메모리에 한번만 저장됩니다.

irb(main):039:0> :a.object_id
=> 751388
irb(main):040:0> a = :a
=> :a
irb(main):041:0> a.object_id
=> 751388
irb(main):042:0> a2 = "a".to_sym
=> :a
irb(main):043:0> a2.object_id
=> 751388
irb(main):044:0>

위처럼 symbol을 어떤식으로 선언, 참조하든지 메모리상의 같은 id를 참조하고 있는 것을 볼 수가 있습니다.

irb(main):044:0> s = "string"
=> "string"
irb(main):045:0> s.object_id
=> 70163601040600
irb(main):046:0> s2 = "string"
=> "string"
irb(main):048:0> s2.object_id
=> 70163600979440
irb(main):049:0> "string".object_id
=> 70163600862200

반면 위처럼 string은 완전히 같은 문자일지라도 새로운 객체를 생성해서 새롭게 메모리에 저장합니다.

 

이렇게 메모리에 저장된 symbol은 all_symbols 메소드로 확인할 수 있습니다.

irb(main):055:0> Symbol.all_symbols.last(5)
=> [:avc, :haeree, :s2, :s3, :a]
irb(main):056:0> Symbol.all_symbols.size
=> 3753

 

3. 언제 symbol을 사용할까?

1) identifier

위에서 알아본 것 처럼 symbol은 immutable하며 메모리에 한번만 저장이 됩니다. 이와같은 특성때문에 symbol은 단순히 문자열을 저장할때보다는 indentifer(구분자)로 사용이 됩니다.

 

example_hash = {a: 'a', b: 'b', c: 'c'}

대표적으로 이렇게 hash의 key로 많이 사용하는데요, symbol의 특성이 key로서 잘 맞을 뿐 아니라 string으로 된 key보다 속도 또한 빠릅니다.

 

gist.github.com/matugm/410f46ca87455b2701faa9a88edee8df

 

strings_vs_symbol_benchmark.rb

GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

이떤 친절한 개발자가 이렇게 직접 비교를 해주었는데요, string을 key로 사용할때가 symbol을 key로 사용할때보다 약 1.7 배 느리다고 합니다.

 

또 이렇게 class를 정의할때 attr_accessor (그 외의 getter setter 메소드를 포함해서)을 사용할때도 사용할 수 있습니다.

irb(main):075:0> class Foo
irb(main):076:1> attr_accessor :name
irb(main):077:1> end
=> nil
irb(main):078:0>
irb(main):079:0> a = Foo.new
=> #<Foo:0x00007fa07992ffb0>
irb(main):080:0> a.name = 'haeree'
=> "haeree"
irb(main):081:0> puts a.name
haeree
=> nil

2. to_proc을 사용할 때

사실 이 부분을 공부하기 위해 포스트를 작성했습니다.

rails 개발을 하다보면 arr.map(&:length) 이런 이상한 문법을 자주 보는데요, 찾아보니 이 문법도 symbol을 이용한 문법이더라고요.

 

Symbol 객체는 to_proc 메소드를 구현하고 있습니다.

 

proc은 block을 캡슐화한 객체입니다. proc과 block (그리고 항상 같이 나오는 lambda) 에 대한 개념은 살짝 복잡해서 다음 포스트에서 한번 정리하도록 하겠습니다.

아무튼 proc을 통해서 우리는 block으로 만든 익명함수를 변수에 저장하고, 이 함수를 다른 메소드에 인자로 넘겨주거나 직접 호출할 수 있습니다.

irb(main):082:0> p = Proc.new do
irb(main):083:1* puts 'hello'
irb(main):084:1> end
=> #<Proc:0x00007fa0790958a0@(irb):82>

irb(main):086:0> p.call
hello
=> nil

irb(main):092:0> def call_func(p)
irb(main):093:1> p.call
irb(main):094:1> end
=> :call_func
irb(main):095:0> call_func p
hello
=> nil

 

이렇게 proc p를 직접 콜하거나 메소드에 넘겨보았는데요, 다시 돌아와서 symbol에 to_proc 메소드가 있다고 했었죠.

 

symbol을 이용하면 이미 존재하는 함수를 proc으로 바꿔서 다른 함수에 인자로 넘길 수 있습니다.

irb(main):184:0> arr = ['hello', 'world','!']
=> ["hello", "world", "!"]
irb(main):186:0> arr.map(&:length)
=> [5, 5, 1]
## 위 코드는 arr.map {|a| a.length}와 같습니다. 

&는 to_proc을 호출해서 객체를 proc으로 만들어주는 연산자입니다.

위 코드에서는 length라는 문자열 함수를 proc으로 바꾼 후 map 함수에 인자로 넘겨주었습니다.

 

 

3. 결론

이렇게 symbol에 대해서 알아봤는데요, 그동안 제대로 공부 안하고 쓰긴 했는데 사용은 다행히 제대로 하고 있었네요. 다행입니다... 최근에는 개인적으로 자바스크립트도 공부하고 있는데 proc 얘기를 한김에 ruby의 함수형 프로그래밍에 대해서 한번 다뤄봐야겠네요. 

 

 

출처:

www.44bits.io/ko/post/ruby-proc-and-lambda

 

루비(Ruby)의 다양한 익명 함수 표현법 - 블록, Proc 객체, 람다(lambda) 함수의 차이 이해하기

프로그래밍 언어 루비에서는 블록 문법이 많이 활용됩니다. 블록 문법은 루비의 익명 함수 표현법 중 하나입니다. 루비에는 블록 뿐만아니라 Proc 객체나 lambda 문을 통해서도 익명 함수를 정의할

www.44bits.io

ruby-doc.org/core-2.2.0/Symbol.html#method-i-to_proc

 

Class: Symbol (Ruby 2.2.0)

Symbol objects represent names and some strings inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods. The same Symbol object will be created for a given name or string for the dura

ruby-doc.org

medium.com/@lcriswell/ruby-symbols-vs-strings-248842529fd9

 

Ruby Symbols vs. Strings

What is a symbol in Ruby?

medium.com

fullstackheroes.com/ruby/symbols-vs-strings/

댓글