ようへいの日々精進XP

よかろうもん

2018 年 05 月 23 日(水)

ジョギング

日課

  • お休み

夕飯

  • 初めての「香華
  • 可もなく不可もなく...

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

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
  @@v = 0
  def initialize
    @@v += 1
  end
end

class Cls2 < Cls1
  class << Cls2
    @@v += 1
  end

  def initialize
    @@v += 1
    super
  end
end

Cls2.new
Cls2.new
Cls1.new
Cls1.new

p Cls2.class_variable_get(:@@v)

以下のように各メソッドでどのような値になっているかを出力しながら irb で確認してみる.

class Cls1
  @@v = 0
  def initialize
    puts "Cls1 #{@@v}"
    @@v += 1
  end
end

class Cls2 < Cls1
  class << Cls2
    puts "Cls2 Class Method #{@@v}"
    @@v += 1
  end

  def initialize
    puts "Cls2 #{@@v}"
    @@v += 1
    super
  end
end

以下, irb の実行結果.

irb(main):022:0> Cls2.class_variable_get(:@@v)
=> 1
irb(main):023:0> Cls2.new
Cls2 1
Cls1 2
=> #<Cls2:0x005586f67be8a0>
irb(main):024:0> Cls2.class_variable_get(:@@v)
=> 3
irb(main):025:0> Cls2.new
Cls2 3
Cls1 4
=> #<Cls2:0x005586f67b40a8>
irb(main):026:0> Cls2.class_variable_get(:@@v)
=> 5
irb(main):027:0> Cls1.new
Cls1 5
=> #<Cls1:0x005586f67a9090>
irb(main):028:0> Cls2.class_variable_get(:@@v)
=> 6
irb(main):029:0> Cls1.new
Cls1 6
=> #<Cls1:0x005586f679dfb0>
irb(main):030:0> Cls2.class_variable_get(:@@v)
=> 7
  • Cls2 にクラスメソッドが定義された時点で +1 となる
  • Cls2.new は Cls2 自身の initialize メソッドが呼ばれた時点で +1, 更に super クラスである Cls1.new の initialize が呼ばれて + 1 = 2
  • Cls2.new = 2 が計 2 回呼ばれているので, Cls2.new x 2 = 4 となる
  • Cls1.new は initialize 時に +1 される
  • Cls1.new = 1 が計 2 回呼ばれているので, Cls1.new x 2 = 2 となる

ということで, 最初のクラスメソッド定義時点で 1 + Cls2.new が 2 度呼ばれて 4 + Cls1 が 2 度呼ばれて 2 = 合計 7 となる.

んー, イマイチ...解らない.

Proc

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

def foo(*args, &block)
  block.call(*args)
end

foo(1,2,3,4) do |*args|
  p args.length > 0 ? "hello" : args
end

hello を出力される

以下, irb による出力例.

irb(main):001:0> def foo(*args, &block)
irb(main):002:1>   block.call(*args)
irb(main):003:1> end
=> :foo
irb(main):004:0> 
irb(main):005:0* foo(1,2,3,4) do |*args|
irb(main):006:1*   p args.length > 0 ? "hello" : args
irb(main):007:1> end
"hello"
=> "hello"

以下, 解説より抜粋.

  1. 1 行目で引数の値を配列として受け取り, ブロックに配列を渡している
  2. 2 行目で * を付けて引数を渡している為, 配列が展開される
  3. 5 行目でブロック変数を渡しているが, *args と宣言されている為, [1, 2, 3, 4] が渡される
  4. 6 行目で args.length > 0 の結果は真となり, hello が出力される

ブロックをメソッドの引数として受け取る例. (プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで を参考にして.)

irb(main):001:0> def words(&b)
irb(main):002:1>   puts 'AAAAA'
irb(main):003:1>   text = b.call('BBBBB')
irb(main):004:1>   puts text
irb(main):005:1>   puts 'CCCCC'
irb(main):006:1> endフムフム
=> :words
irb(main):007:0> 
irb(main):008:0* words do |text|
irb(main):009:1*   text * 2
irb(main):010:1> end
AAAAA
BBBBBBBBBB
CCCCC
=> nil
irb(main):001:0> def words(*arg, &b)
irb(main):002:1>   puts 'AAAAA'
irb(main):003:1>   puts arg
irb(main):004:1>   text = b.call(*arg)
irb(main):005:1>   puts text
irb(main):006:1>   puts 'CCCCC'
irb(main):007:1> end
=> :words
irb(main):008:0> 
irb(main):009:0* 
irb(main):010:0* words('a', 'b') do |*text|
irb(main):011:1*   text * 2
irb(main):012:1> end
AAAAA
a
b
a
b
a
b
CCCCC
=> nil

フムフム.