Hash#diff - 메서드 연쇄의 재미
이전글 - Numeric#bytes - 열린 클래스와 DSL 전체보기
뿌요뿌요라는 게임이 있습니다. 이 게임의 재미는 최대한 많이 잘 쌓아서, 한번에 몽땅 없애버리는 ‘연쇄’를 만드는데 있습니다. 해보신 분들은 알겠지만, 거기서 오는 묘한 쾌감이 있지요. 루비에도 비슷한 것이 있습니다. 바로 메서드 연쇄(method chaining)입니다. 뿌요뿌요 19연쇄만큼은 아니겠지만, 그래도 꽤 재미있습니다.
책에서도 설명하였듯, 루비에서는 대부분의 명령이 표현식입니다(7장 참조). 어디서든 의미 있는 반환값을 제공하자는 규약과 메서드에서 명시적인 return문이 없어도 마지막 실행 값이 반환값이 되는 특징이 합쳐져서 일어난 결과입니다. 그래서 다음과 같은 코드가 무척 자연스럽습니다.
- [3,1,7,0].sort.reverse
심지어는 if문도 반환값이 있습니다. 이런 표현도 가능하지요.
- where_to_to = if season == 'summer'
'beach'
else
'stay_home'
end
조금 어색하기는 하지만, 가끔 유용한 경우가 있습니다. 루비의 이런 특성이 빛을 바라는 코드가 하나 더 있습니다. 다음을 보세요.
- (keys ||= []) << 'value'
위 문장을 풀어 쓰면 이렇게 됩니다.
- keys = (keys ? keys : [])
keys << 'value'
|| 연산자와 대입문이 의미 있는 값을 반환하는 표현식이기 때문에 저런 연쇄(축약) 표현이 가능해집니다. 참고로 || 연산자는 매개변수 중 참, 거짓을 결정하는 값을 반환합니다. keys || []라는 표현식에서는 keys가 참이면 표현식도 참이 되므로 keys를 반환하고, keys가 거짓이면 이 표현식의 값은 []에 의해 좌우되므로 []를 반환합니다. 그리고 대입문은 대입의 결과를 반환합니다.
연쇄를 오남용하면 쓸데없이 길기만하고 난해가 코드가 되기도 하지만 위 문장처럼 단순 명료해지기도 합니다. 그리고 메서드를 작성할 때 항상 의미 있는 반환값에 조금 더 신경을 써야합니다.
액티브 서포트에서도 메서드 연쇄를 이용해 문제를 간단하게 해결해버린 예가 있어서 소개합니다. 두 개의 해시가 있을 때, 이 해시들의 차이(diff)를 구하고자 합니다. 어떻게 할 수 있을지 잠시 생각해보세요.
h1, h2가 있다고 했을 때, h1 중 값이 h2에 있는 것을 지워주고, h2에서 h1에 같은 키가 있는 것을 지워주고, 이 두 결과를 하나의 해시로 합쳐주면 됩니다. 루비에서는 간단하게 한 줄로 해결할 수 있습니다. 액티브 서포트의 소스를 보세요.
- class Hash
def diff(h2)
self.dup.delete_if { |k, v| h2[k] == v }.merge(
h2.dup.delete_if { |k, v| self.has_key?(k) })
end
end
{6=>7, 1=>2, 2=>1}.diff 6=>7, 1=>3, 1=>3
#=> {1=>2, 2=>1}
블럭도 없고 적극적인 연쇄도 없는 언어라면 몇 줄이나 써야 했을지 아찔하네요. 끝으로 당부하나, 아무리 재미있어도 너무 이어 쓰지는 마세요. 어느 순간 암호가 되어버린 코드를 보고 기겁하게 될 테니까요 ![]()
- 강문식
History
Last edited on 06/20/2007 21:15 by deepblue
Comments (0)