ようへいの日々精進XP

よかろうもん

2018 年 06 月 27 日 (水)

ジョギング

  • 自宅→香椎宮香椎浜で 35 分くらい
  • 左足足底筋の痛み
  • 右足膝周り痛い
  • 蒸し暑い

日課

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

体調

  • 昨日よりはマシ

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

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)

Module.nesting

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

module SuperMod
end

module SuperMod::BaseMod
  p Module.nesting
end

以下, 解答.

[SuperMod::BaseMod]

以下, irb にて確認.

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

以下, 解説より抜粋.

  • Module.nesting はモジュールやクラスのネストの状態を表示する
  • モジュールがネストされている場合, ネストの全ての状態を表示する
  • インデントして別々に書いた場合 (module SuperMod;module BaseMod; p Module.nesting; end ;end) に比べて, プレフィックス (SuperMod::BaseMod) がある場合は内側にあるモジュールしかネストの状態は表示されない
irb(main):001:0> module SuperMod
irb(main):002:1>   p Module.nesting
irb(main):003:1> end
[SuperMod]
=> [SuperMod]
irb(main):004:0> 
irb(main):005:0* module SuperMod
irb(main):006:1>   module BaseMod
irb(main):007:2>     p Module.nesting
irb(main):008:2>   end
irb(main):009:1> end
[SuperMod::BaseMod, SuperMod]
=> [SuperMod::BaseMod, SuperMod]
irb(main):010:0> 
irb(main):011:0* module SuperMod::BaseMod
irb(main):012:1>   p Module.nesting
irb(main):013:1> end
[SuperMod::BaseMod]
=> [SuperMod::BaseMod]

変態的な定数参照

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

class Ca
  CONST = "001"
end

class Cb
  CONST = "010"
end

class Cc
  CONST = "011"
end

class Cd
  CONST = "100"
end

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

        class C2 < Cb
        end
      end
    end
  end
end

以下, 解答.

100 が表示される

以下, 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
"100"
=> nil

以下, 解説より抜粋.

  • Rubyは定数の参照はレキシカルに決定されるが, 設問ではレキシカルスコープに定数は存在しない
  • レキシカルスコープに定数が存在しない場合, スーパークラスの探索を行う

レキシカルスコープとは...

  • 変数を参照する仕様の一つ (ダイナミックスコープというのもある)
  • 他の関数のローカル変数は参照することが出来ない
  • 設問でのレキシカルスコープとは, module M1 ~ end までになるんだと思う

以下, 設問を利用して実験.

class Ca
  CONST = '001'
end

class Cb
  CONST = '002'
end

module M1
  class C0 < Ca
    class C1 < Cb
      p CONST
    end
  end
end

これを実行すると, 以下のように 002 が出力される.

... 略 ...
irb(main):008:0> 
irb(main):009:0* module M1
irb(main):010:1>   class C0 < Ca
irb(main):011:2>     class C1 < Cb
irb(main):012:3>       p CONST
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
"002"
=> "002"

では, 以下のように定数 CONST を定義した場合にどうなるか.

... 略 ...
module M1
  class C0 < Ca
    CONST = 'aaaaaaaaaaaaaa'
    class C1 < Cb
      p CONST
    end
  end
end

以下のように aaaaaaaaaaaaaa と出力される.

irb(main):016:0> module M1
irb(main):017:1>   class C0 < Ca
irb(main):018:2>     CONST = 'aaaaaaaaaaaaaa'
irb(main):019:2>     class C1 < Cb
irb(main):020:3>       p CONST
irb(main):021:3>     end
irb(main):022:2>   end
irb(main):023:1> end
"aaaaaaaaaaaaaa"
=> "aaaaaaaaaaaaaa"

これは, レキシカルスコープ内に定数が定義されていると言える. 対して, 以下のように定義した場合にどうなるか.

... 略 ...
CONST = 'aaaaaaaaaaaaaa'
module M1
  class C0 < Ca
    class C1 < Cb
      p CONST
    end
  end
end

以下のように 002 と表示される.

... 略 ...
irb(main):008:0> CONST = 'aaaaaaaaaaaaaa'
=> "aaaaaaaaaaaaaa"
irb(main):009:0> module M1
irb(main):010:1>   class C0 < Ca
irb(main):011:2>     class C1 < Cb
irb(main):012:3>       p CONST
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
"002"
=> "002"

これは, 定数がレキシカルスコープに無い為, スーパークラスを探索して定数を参照している.

フムフム.