ruby > module 정의할 때 double colon

Dongyoon Lee·2020년 9월 6일

로직이 워낙 많아져서 모듈 여러개를 모듈에 넣어서 그 모듈을 extend 하는 방식으로 코드를 키워 나가는 중에, 모듈 선언하는 방식과 로딩 순서에 따라 동작이 다른 듯 하여, 필요한 만큼만 검색, 테스트로 살짝 파봤다.

결론부터 말하자면, lexical scope 을 먼저, 그 후에 inheritance 구조를 타면서 찾는다.

아래 코드는 위 링크에서 뽑아온 코드고, 이렇게 짜야 한다는 뜻은 아니다. 이런 특이한 상황은 마주하지 않고 피하는 것이 최선

1.

module A
  module B
    PI = 3.14
    module C
      class E
        PI = 3.15
      end
      class F < E
        def get_pi
          puts PI
        end
      end
    end
  end
end
f = A::B::C::F.new
f.get_pi
> 3.14

lexical scope 를 1차로 확인하고, 그 후에 inheritance hierarchy 를 확인하기 때문에 3.15 대신 3.14 를 얻게 됨.

만약 B 모듈의 PI 선언을 주석처리한다면? 결과는 3.15 가 나온다.

2.

module A
end

module A::B
  PI = 3.14
end

module A::B::C
  class D
    def get_pi
      puts PI
    end
  end
end
d = A::B::C::D.new
d.get_pi
NameError: uninitialized constant A::B::C::D::PI
Did you mean?  A::B::PI

A::B::C 처럼 :: (namespace resolution operator) 를 사용해서 선언하게 되면 lexical scope 을 벗어나게 돼서, 위처럼 에러가 난다.

아래처럼 선언하면?

module A
  module B
    module C
      class D
        ...

3.14 출력.

또, 아래처럼 선언하면?

module A::B
  module C
    class D
      ...

3.14 출력.

3.

module A
  A_CONSTANT = 1
  module B
    B_CONSTANT = 2
  end
end

module A # open A’s scope
  module B # open B’s scope under A
    p B_CONSTANT
    p A_CONSTANT
  end
end

module A::B # open B’s scope without opening A
  p B_CONSTANT # B constants are resolved
  p A_CONSTANT # This throws a NameError unless A_CONSTANT is defined in B or TOPLEVEL
end

출력 결과는 2, 1, 2

마지막 p 만 에러가 발생한다.


2020

7/31 최초 작성.

profile
입코딩 용사

0개의 댓글