(본 게시물은 저작권의 문제 발생시 출판사의 요청에 의해 삭제될 수 있습니다.)
조건적 실행
논리 표현식
루비에서는 매우 간단한 참의 정의를 가지고 있다. nil과 상수 false가 아닌 모든 것은 참(true)이다. 예를 들어 "cat", 99, 0, :a_song은 모두 true이다.
nil이 false로 다뤄지는 것은 매우 편리하다. 예를 들어 IO#gets는 파일의 다음 행을 읽어오는데 더 이상 읽어올 행이 없을 때는 nil을 반환한다. 따라서 다음과 같은 반복문 작성이 가능하다.
while line = gets
# 처리
end
하지만 주의할 점은 숫자 0이 false로 해석되지 않는다는 점이다. 길이가 0인 문자열도 마찬가지이다.
and, or, not
루비는 모든 표준 논리 연산자를 지원한다. and와 &&는 첫 번째 피연산자가 false이면 첫 번째 피연산자를 그대로 반환한다. 그 외에는 두 번째 피연산자를 평가하고 그 값을 반환한다. &&와 and의 유일한 차이는 연산자 우선순위다. and는 &&보다 우선순위가 낮다.
nil && 99 # => nil
false && 99 # => false
"cat" && 99 # => 99
따라서 &&와 and는 모두 피연산자들이 모든 참일 때만 참을 반환한다. or과 | | 는 첫 번째 피연산자가 거짓이 아니면 이를 그대로 반환한다. 첫 번째 피연산자가 거짓이면 두 번째 피연산자를 평가하고 그 결과를 반환한다.
nil | | 99 # => 99
false | | 99 # => 99
"cat" | | 99 #=> "cat"
and와 마찬가지로 or과 | |의 차이도 우선순위에 있다 흥미로운 점은 and와 or은 우선순위가 같은데 &&는 | |보다 우선순위가 높다. | | =은 어떤 변수에 아무런 값이 없다면 대입을 하라는 이믜의 관용구로 자주 사용된다.
var | | = "default value"
var = var | | "default value"와 같은 표현이다. 변수에 이미 대입이 이뤄져 있다면 대입하지 않는다. 의사코드로 작성하자면
var = "default value " unless var나 as var | | var = "default value"가 된다.
not과 !는 피연산자를 반전한 값을 반환한다. 즉 피연산자가 거짓이면 true, 참이면 false를 반환한다.
defined?
defined? 연산자는 매개 변수가 정의되지 않았을 때 nil을 반환하며, 그렇지 않은 경우 매개 변수에 대한 설명을 반환한다. 매개 변수가 yield문이라면 defined?는 현재의 문맥에 블록이 결합된 경우에 한해 yield를 반환한다.
defined? 1 # => "expression"
defined? dummy # => nil
defined? printf # => "method"
defined? String # => "constant"
defined? $_ # => "gloabal-variable"
defined? a = 1 # => "assign"
defined? 42.abs # => "method"
defined? nil #=> "nil"
객체 비교하기
논리 연산자와 더불어 루비 객체는 ==, ===, <=>, =~, eql?, equal? 등의 메서드를 통해 객체 간의 비교를 지원한다. <=>를 제외한 모든 메서드가 Object에 정의되어 있지만 하위 클래스에서 재정의 되는 일이 빈번하다.
== : 두 값이 같은지 비교한다.
=== : case 구문의 when 항목이 비교할 대상과 동일한지 비교하는 데 쓰인다.
<=> : 일반적인 비교 연산자. 수신자가 매개 변수보다 작으면 -1, 같으면 0, 크면 1을 반환한다.
<, <=, >=, > : 작다 / 작거나 같다/ 크거나 같다/ 크다를 의미하는 비교 연산자.
=~ : 정규 표현식 패턴이 매치되는지 검사한다.
eql? : 수신자와 매개 변수가 서로 같은 타입이며 같은 값을 가지는 경우 참이 된다. 1 == 1.0은 true이지만, 1.equl?(1.0)은 false이다.
==와 =~의 부정 연산자는 각각 !=와 !~이다. 다음 예제는 비교 연산자로 == 만 사용된다.
class T
def == (other)
puts "Comparing self == #{other}"
other == "value"
end
end
t = T.new
p(t == "value")
p(t != "value")
실행결과
Comparing self == value
true
Comparing self == value
false
명시적으로 !=가 정의되면 루비는 이를 사용한다.
class T
def ==(other)
puts "Comparing self == #{other}"
other == "value"
end
def !=(other)
puts "Comparing self != #{other}"
other != "value"
end
end
t = T.new
p(t == "value")
p(t != "value")
실행결과
Comparing self == value
true
Comparing self == value
false
루비의 범위 또한 논리식으로 이용할 수 있다. 범위 exp1..exp2는 exp1이 참이 될 때까지 거짓으로 평가되고 exp2가 참이 될 때까지 참으로 평가된다. exp2가 true가 되면 리셋되고 다시 같은 과정을 반복한다.
if와 unless 표현식
루비의 if 식은 다른언어와 매우 비슷하다.
if artist == "Gillespie" then
#
elseif artist == "Parker" then
#
else
#
end
if 문을 여러 줄에 걸쳐 작성할 때는 then을 생략할 수 있다.
if artist == "Gillespie"
#
elsif artist == "Parker"
end
elsif를 사용하지 않거나 여러 개의 elsif를 사용할 수 있다. elsif에서 가운데 e가 없다는 점에 주의가 필요하다. 앞에서도 이야기 했듯이 if는 표현식이지 구문이 아니다. if 식은 값을 반환한다. if 표현식의 값을 반드시 이용할 필요는 없지만 유요할 때도 있다.
handle = if artist == "Gillespie"
#
elsif artist == "Parker"
#
else
#
end
루비에는 if의 부정형도 있다.
unless duration > 100
#blabla~
end
if와 unless 변경자
루비는 펄의 간결한 기능을 물려받았다. 구문 변경자는 조건문을 일반 구문의 끝이 붙여서 사용할 수 있게 해준다.
mon, day, year = $1, 42, $3 if date =~ /(\d\d)-(\d\d)-(\d\d)/
puts "a = #{a}" if #DEBUG
print total unless total.zero?
if구문 변경자를 예로 들면, 앞에 오는 표현식은 조건이 참일 때만 계산된다. 그리고 unless는 그 반대로 동작한다.
File.foreach("/etc/passwd") do | line |
next if line =~ /^#/ #주석은 건너뛴다.
parse(line) unless line =~ /^$/
end
끄읕