Ruby 변수 생성

Posted 2007. 2. 18. 01:02
루비에서 변수 생성에 대한 규칙을 잘못 알고 있었다.

[skyul@dev ~]$ irb
irb(main):001:0> a
NameError: undefined local variable or method `a' for main:Object
        from (irb):1
irb(main):002:0> a = 1 if false
=> nil
irb(main):003:0> a
=> nil
irb(main):004:0>

처음 irb를 동작시키면 a라는 변수(혹은 메쏘드)가 정의되어 있지 않으므로 undefiend local variable or method 'a'라는 에러 메시지를 출력한다. 다음으로 실행한 구문은 a = 1 if false이다. if false는 무조건 거짓이므로 a = 1은 절대로 실행되지 않는다. 문제는 다음 행이다. 직관적으로 판단하기에 a = 1이라는 대입(assignment)가 일어나지 않았으므로 a는 여전히 undefiend 일 것이라 생각했지만, 예상과는 달리 a = nil이다.  즉 루비는 a = 1이 대입이 일어나야만 a 변수를 생성해 주는 것이 아닌 것이다. 프로그램을 차례대로 읽으면서 조건에 상관없이 a가 변수로 사용되었음을 알았기 때문에 그 후로는 a를 정의해 준 것이다.

로컬 변수와 메쏘드를 구분하는 것도 마찬가지이다. 다음은 "Programming Ruby: The Ruby Language, Variable/Method Ambiguity"에서 따온 예제이다.

def a
  print "Function 'a' called\n"
  99
end

for i in 1..2
  if i == 2
    print "a=", a, "\n"
  else
    a = 1
    print "a=", a, "\n"
  end
end

결과

a=1
Function 'a' called
a=99


위 예제는 a가 함수로도 사용될 수 있고, 변수로도 사용될 수 있음을 보여준다. a = 1 구문을 지나고 나면 a가 변수임을 알고, 변수로 호출한다. i == 2인 경우 이미 a에 1라는 변수가 할당되어 있지만 앞쪽에 나와있기 때문에 a = 1이라는 대입이 있었음을 알지 못한다. 따라서 이 경우 a를 메쏘드로 가정하는 휴리스틱을 사용한다.

다음과 같이 i == 1 조건이 먼저 나오면 어떨까?

for i in 1..2
  if i == 1
    a = 1
    print "a=", a, "\n"
  else
    print "a=", a, "\n"
  end
end

이 경우 a = 1 대입은 i == 1인 조건에만 있지만, 이 조건이 else 구문보다 앞서 있기 때문에 둘 다 a를 변수로 인식하고 1을 출력할 것이다.

a=1
a=1