ようへいの日々精進XP

よかろうもん

2018 年 06 月 08 日 (金)

ジョギング

日課

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

奥さん

  • 体調を崩した
  • 疲れがたまっていたのだろう, 週末はゆっくりとして欲しい

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

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)

クラスの継承

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

class Cls1
  def initialize
    puts "Cls1#initialize"
  end
end

class Cls2 < Cls1
  def initialize(*args)
    super
    puts "Cls2#initialize"
  end
end

Cls2.new(1,2,3,4,5)

例外 (ArgumentError) が発生する

以下, irb にて確認.

...
irb(main):013:0> 
irb(main):014:0* Cls2.new(1,2,3,4,5)
ArgumentError: wrong number of arguments (5 for 0)
...

以下, 解説より抜粋.

  • super と呼び出した場合は, 現在のメソッドと同じ引数が引き継がれる
  • 引数を渡さずにオーバーライドしたメソッドを呼び出す際は super() と指定する
  • super() とするか, 親クラスの def initialize メソッドを def initialize(*) とすることで, 子クラスの同名メソッドの引数を無名引数として受け取ることが出来る

以下, コードの修正案.

# パターン 1
class Cls1
  def initialize
    puts "Cls1#initialize"
  end
end

class Cls2 < Cls1
  def initialize(*args)
    super()
    puts "Cls2#initialize"
  end
end

Cls2.new(1,2,3,4,5)

# パターン 2
class Cls1
  def initialize(*)
    puts "Cls1#initialize"
  end
end

class Cls2 < Cls1
  def initialize(*args)
    super
    puts "Cls2#initialize"
  end
end

Cls2.new(1,2,3,4,5)

修正案を irb で確認.

# パターン 1
irb(main):001:0> class Cls1
irb(main):002:1>   def initialize
irb(main):003:2>     puts "Cls1#initialize"
irb(main):004:2>   end
irb(main):005:1> end
=> :initialize
irb(main):006:0> 
irb(main):007:0* class Cls2 < Cls1
irb(main):008:1>   def initialize(*args)
irb(main):009:2>     super()
irb(main):010:2>     puts "Cls2#initialize"
irb(main):011:2>   end
irb(main):012:1> end
=> :initialize
irb(main):013:0> Cls2.new(1,2,3,4,5)
Cls1#initialize
Cls2#initialize
=> #<Cls2:0x005587ff14d750>

# パターン 2
irb(main):001:0> class Cls1
irb(main):002:1>   def initialize(*)
irb(main):003:2>     puts "Cls1#initialize"
irb(main):004:2>   end
irb(main):005:1> end
=> :initialize
irb(main):006:0> 
irb(main):007:0* class Cls2 < Cls1
irb(main):008:1>   def initialize(*args)
irb(main):009:2>     super
irb(main):010:2>     puts "Cls2#initialize"
irb(main):011:2>   end
irb(main):012:1> end
=> :initialize
irb(main):013:0> 
irb(main):014:0* Cls2.new(1,2,3,4,5)
Cls1#initialize
Cls2#initialize
=> #<Cls2:0x0055ef9b3d0e60>

定数参照

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

class Cls1
  CONST = "aaa"
end

module Mod
  CONST = "bbb"
end

module Mod
  class Cls1
    CONST = "ccc"
  end
end

module Mod
  class ::Cls1
    p CONST
  end
end

aaa が表示される

以下, irb にて確認.

irb(main):001:0> class Cls1
irb(main):002:1>   CONST = "aaa"
irb(main):003:1> end
=> "aaa"
irb(main):004:0> 
irb(main):005:0* module Mod
irb(main):006:1>   CONST = "bbb"
irb(main):007:1> end
=> "bbb"
irb(main):008:0> 
irb(main):009:0* module Mod
irb(main):010:1>   class Cls1
irb(main):011:2>     CONST = "ccc"
irb(main):012:2>   end
irb(main):013:1> end
=> "ccc"
irb(main):014:0> 
irb(main):015:0* module Mod
irb(main):016:1>   class ::Cls1
irb(main):017:2>     p CONST
irb(main):018:2>   end
irb(main):019:1> end
"aaa"
=> "aaa"

以下, 解説より抜粋.

  • クラス名が修飾されている場合は同じ名前であっても別のクラスになるが, :: 演算子を使うことによりネストを指定することができる
  • モジュール Mod にあるクラス Cls1 でメソッドの呼び出しを行う為には, M::C と書く
  • 先頭に :: をつけるとトップレベルから探索を行う
  • 設問では ::Cls1 となっており, トップレベルの ::Cls1 を参照する為, aaa が表示される

フムフム.