ようへいの日々精進XP

よかろうもん

2018 年 05 月 30 日 (水)

ジョギング

日課

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

蒸し暑くなってきた...

  • 走った後とか辛い

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

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)

Enumerator クラス, Enumerable クラス, String クラス, Object クラス

以下のプログラムを実行すると, ruby が一文字ずつ表示される. each_char を置き換えても同じ結果になるメソッドを選択肢から選ぶ.

enum = 'ruby'.each_char
p enum.next
p enum.next
p enum.next
p enum.next

とりあえず, 上記を irb で試す.

irb(main):001:0> enum = 'ruby'.each_char
=> #<Enumerator: "ruby":each_char>
irb(main):002:0> p enum.next
"r"
=> "r"
irb(main):003:0> p enum.next
"u"
=> "u"
irb(main):004:0> p enum.next
"b"
=> "b"
irb(main):005:0> p enum.next
"y"
=> "y"
irb(main):001:0> enum = 'ruby'.enum_for(:each_char)
=> #<Enumerator: "ruby":each_char>
irb(main):002:0> p enum.next
"r"
=> "r"
irb(main):003:0> p enum.next
"u"
=> "u"
irb(main):004:0> p enum.next
"b"
=> "b"
irb(main):005:0> p enum.next
"y"
=> "y"

ちなみに, String#nextInteger#next は, それぞれ succ メソッドをエイリアスとして利用可能であるが, Enumerator#next には succ は存在しないので注意する.

ということで, 解答.

to_enum(:each_char) enum_for(:each_char)

以下, irb で確認.

irb(main):006:0> enum = 'ruby'.to_enum(:each_char)
=> #<Enumerator: "ruby":each_char>
irb(main):007:0> p enum.next
"r"
=> "r"
irb(main):008:0> p enum.next
"u"
=> "u"
irb(main):009:0> p enum.next
"b"
=> "b"
irb(main):010:0> p enum.next
"y"
=> "y"

以下, 解説より抜粋.

  • each_char にブロックを渡さない場合は, Enumerator オブジェクトが作成される
  • Enumerator オブジェクトを作成するには, enum_for または, to_enum を利用する
  • 引数にはレシーバーに送信したいメッセージ (メソッドの呼び出し) を定義する
  • 引数を指定しない場合は, each がデフォルト値になる

次の例では、eachを使って1つずつアクセスして要素を表示しています。

irb(main):001:0> enum = [1, 2, 3, 4, 5].to_enum
=> #<Enumerator: [1, 2, 3, 4, 5]:each>
irb(main):002:0> p enum.next
1
=> 1
irb(main):003:0> p enum.next
2
=> 2
irb(main):004:0> p enum.next
3
=> 3
irb(main):005:0> p enum.next
4
=> 4
irb(main):006:0> p enum.next
5
=> 5
irb(main):001:0> enum = [1, 2, 3, 4, 5].enum_for(:reverse_each)
=> #<Enumerator: [1, 2, 3, 4, 5]:reverse_each>
irb(main):002:0> p enum.next
5
=> 5
irb(main):003:0> p enum.next
4
=> 4
irb(main):004:0> p enum.next
3
=> 3
irb(main):005:0> p enum.next
2
=> 2
irb(main):006:0> p enum.next
1
=> 1

例外

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

begin
  print "foo" + :bar
rescue TypeError
  print "TypeError."
rescue
  print "Error."
else
  print "Else."
end

TypeError. が表示される

以下, irb による確認.

irb(main):001:0> begin
irb(main):002:1*   print "foo" + :bar
irb(main):003:1> rescue TypeError
irb(main):004:1>   print "TypeError."
irb(main):005:1> rescue
irb(main):006:1>   print "Error."
irb(main):007:1> else
irb(main):008:1*   print "Else."
irb(main):009:1> end
TypeError.=> nil

以下, 解説より抜粋.

  • String#+String クラスのオブジェクトを期待する
  • 引数に Symbol クラスを渡している為, 例外 TypeError が発生する
  • else ブロックは例外が発生しない場合に実行される

ちなみに, 以下のように書くとどうなるか.

begin
  print "foo" + :bar
rescue TypeError
  print "TypeError."
rescue
  print "Error."
else
  print "Else."
ensure
  print "Ensure."
end

Type Error. と Ensure. が出力される

以下, irb による実行例.

irb(main):001:0> begin
irb(main):002:1*   print "foo" + :bar
irb(main):003:1> rescue TypeError
irb(main):004:1>   print "TypeError."
irb(main):005:1> rescue
irb(main):006:1>   print "Error."
irb(main):007:1> else
irb(main):008:1*   print "Else."
irb(main):009:1> ensure
irb(main):010:1*   print "Ensure."
irb(main):011:1> end
TypeError.Ensure.=> nil

ensure ブロックは例外の発生関わらず, 必ず実行されるので, このコードにおいて例外が発生しない場合には, else 及び ensure ブロックまで含まれる出力となる.

irb(main):001:0> begin
irb(main):002:1*   print "foo" + 'bar'
irb(main):003:1> rescue TypeError
irb(main):004:1>   print "TypeError."
irb(main):005:1> rescue
irb(main):006:1>   print "Error."
irb(main):007:1> else
irb(main):008:1*   print "Else."
irb(main):009:1> ensure
irb(main):010:1*   print "Ensure."
irb(main):011:1> end
foobarElse.Ensure.=> nil

フムフム.