ようへいの日々精進XP

よかろうもん

2018 年 05 月 28 日 (月)

天気

  • 小雨からの曇
  • 梅雨入り

ジョギング

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

夕飯

  • 手羽中の磯辺揚げ風
  • ピーマンと新玉ねぎの天ぷらっぽいやつ

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (11) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

mix-in

以下のコードを実行するとどうなるか.

module Mod1
end

module Mod1::Mod2
  p Module.nesting
end

Mod1::Mod2

以下, irb による動作確認.

irb(main):001:0> module Mod1
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module Mod1::Mod2
irb(main):005:1>   p Module.nesting
irb(main):006:1> end
[Mod1::Mod2]
=> [Mod1::Mod2]

以下, 解説より抜粋.

  • Module.nesting はネストの状態を表示する
  • モジュールがネストされている場合には, ネストの状態をすべて表示する
  • Mod1::Mod2 のようにプログラムを書くとモジュール Mod1 の内側にモジュール Mod2 があることを表現することが出来る
  • インデントして個別に書いた場合と比較して, プレフィックス (::) がある場合は内側にあるモジュールしかネストの状態は表示されない
irb(main):001:0> module Mod1
irb(main):002:1>   p Module.nesting
irb(main):003:1> end
[Mod1]
=> [Mod1]
irb(main):004:0> module Mod1::Mod2
irb(main):005:1>   p Module.nesting
irb(main):006:1> end
[Mod1::Mod2]
=> [Mod1::Mod2]
irb(main):007:0> module Mod1
irb(main):008:1>   module Mod2
irb(main):009:2>     p Module.nesting
irb(main):010:2>   end
irb(main):011:1> end
[Mod1::Mod2, Mod1]
=> [Mod1::Mod2, Mod1]
irb(main):012:0> 
irb(main):012:0> module Foo
irb(main):013:1>   module Bar
irb(main):014:2>     module Baz
irb(main):015:3>       p Module.nesting
irb(main):016:3>     end
irb(main):017:2>   end
irb(main):018:1> end
[Foo::Bar::Baz, Foo::Bar, Foo]
=> [Foo::Bar::Baz, Foo::Bar, Foo
irb(main):019:0> class Cls1
irb(main):020:1>   class Cls2
irb(main):021:2>     class Cls3
irb(main):022:3>       Module.nesting
irb(main):023:3>     end
irb(main):024:2>   end 
irb(main):025:1> end
=> [Cls1::Cls2::Cls3, Cls1::Cls2, Cls1

尚, Module.nesting はモジュールだけでなく, クラスについても同様にメソッドを呼び出した時点のネスト情報を配列に入れて返す.

定数

以下のプログラムを実行するとどうなるか.

class Ca
  CONST = "A"
end

class Cb
  CONST = "B"
end

class Cc
  CONST = "C"
end

class Cd
  CONST = "D"
end

module M1
  class C0 < Ca
    class C1 < Cc
      class C2 < Cd
        p CONST

        class C2 < Cb
        end
      end
    end
  end
end

D が出力される

以下, irb で確認.

... 略
irb(main):017:0* module M1
irb(main):018:1>   class C0 < Ca
irb(main):019:2>     class C1 < Cc
irb(main):020:3>       class C2 < Cd
irb(main):021:4>         p CONST
irb(main):022:4> 
irb(main):023:4*         class C2 < Cb
irb(main):024:5>         end
irb(main):025:4>       end
irb(main):026:3>     end
irb(main):027:2>   end
irb(main):028:1> end
"D"
=> nil

以下, 解説より抜粋.

  • Rubyは定数参照はレキシカル (≒静的に) に決定されるが, 設問ではレキシカルスコープに定数は定義されていない
  • レキシカルスコープに定数がない場合は, スーパークラスの探索を行う
  • 設問では, クラス C2 のスコープで定数を参照する
  • クラス C2スーパークラスはクラス Cd となるので, "D" が正解となる

レキシカル又は,レキシカルスコープについては, フワッとしか認識しかないので機会があれば掘り下げたい. 今のところは, スコープ外の同名変数に影響を与えないというくらいのフワッとした認識しかない...

フムフム.