ようへいの日々精進XP

よかろうもん

2018 年 07 月 05 日 (木)

ジョギング

  • おやすみ

日課

  • おやすみ

東京出張

  • 武川さんと色々と話したり, 計画作業を 2 件こなしたり
  • 大住さんと新橋の立ち呑み屋さんで色々と話しが出来てよかった

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

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)

文法 (論理演算子)

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

v1 = 1 / 2 == 0
v2 = !!v1 or raise RuntimeError
puts v2 and false

以下, 解答.

true が表示される

以下, irb にて確認.

irb(main):001:0> v1 = 1 / 2 == 0
=> true
irb(main):002:0> v2 = !!v1 or raise RuntimeError
=> true
irb(main):003:0> puts v2 and false
true
=> nil

以下, 解説より抜粋.

  • 1 行目では Fixnum クラス同士の除算は Fixnum クラスとなり, 0 == 0 が評価され true となる
  • 2 行目の or では左辺が真であれば, 右辺は評価されず, 左辺の結果が返る
  • !!v1 は否定 (!) の否定 (!) となる為, true となり, 左辺が true となっているので v2 には true が代入される
  • 3 行目の and は左辺が真であれば, 右辺の結果を返し, 左辺が偽であれば左辺の結果を返すが, and は優先度が低い演算子である為, puts v2 が評価される

and, or, not の優先度

  • 論理積 (&&), 論理和 (||), 否定 (!) に対応するもので, これらと同様の動きをする
  • 両者の違いは, 自己代入出来ないこと, 代入演算子よりも演算子の優先度が低いことなどが挙げられる

以下, &&and の違い.

# p (1 && 2) と同義
irb(main):006:0> p 1 && 2
2
=> 2
# p (1) and 2 と同義
irb(main):007:0> p 1 and 2
1
=> 2
  • p 1 && 21 && 2論理積の結果が p に渡されている
  • p 1 and 2p 1 の実行結果と 2論理積が渡されている

以下のように and を利用する場合, 二重括弧を利用することで, && と同等の結果を得ることが出来る.

irb(main):008:0> p (1 && 2)
2
=> 2
irb(main):009:0> p ((1 and 2))
2
=> 2

or は, 左辺を評価して結果が真であった場合にはその値を返し, 左辺の評価結果が偽であった場合には右辺を評価してその評価結果を返す. or についても and と同様に p false の実行結果と true が評価される (or の優先度が低い)為, 以下のような結果となる.

irb(main):019:0> p false || true
true
=> true
irb(main):020:0> p false or true
false
=> true

not は, 式の値が真である時には を, 偽であるには真を返す.

irb(main):024:0> p ! true
false
=> false
irb(main):025:0> p not true
SyntaxError: (irb):25: syntax error, unexpected keyword_true, expecting '('
irb(main):028:0> p (! false)
true
=> true
irb(main):030:0> p ((not false))
true
=> true

Enumerable と Enumerator

次のプログラムを実行するために __(1)__ に適切なメソッドをすべて選ぶ.

class IPAddr
  include Enumerable

  def initialize(ip_addr)
    @ip_addr = ip_addr
  end

  def each
    return __(1)__ unless block_given?

    @ip_addr.split('.').each do |octet|
      yield octet
    end
  end
end

addr = IPAddr.new("192.10.20.30")
enum = addr.each

p enum.next # 192と表示される
p enum.next # 10と表示される
p enum.next # 20と表示される
p enum.next # 30と表示される

以下, 解答.

to_enum enum_for

以下, irb にて確認.

irb(main):001:0> class IPAddr
irb(main):002:1>   include Enumerable
irb(main):003:1> 
irb(main):004:1*   def initialize(ip_addr)
irb(main):005:2>     @ip_addr = ip_addr
irb(main):006:2>   end
irb(main):007:1> 
irb(main):008:1*   def each
irb(main):009:2>     return to_enum unless block_given?
irb(main):010:2> 
irb(main):011:2*     @ip_addr.split('.').each do |octet|
irb(main):012:3*       yield octet
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
=> :each
irb(main):016:0> 
irb(main):017:0* addr = IPAddr.new("192.10.20.30")
=> #<IPAddr:0x005611774ad498 @ip_addr="192.10.20.30">
irb(main):018:0> enum = addr.each
=> #<Enumerator: #<IPAddr:0x005611774ad498 @ip_addr="192.10.20.30">:each>
irb(main):020:0> enum.next
=> "192"
irb(main):021:0> enum.next
=> "10"
irb(main):022:0> enum.next
=> "20"
irb(main):023:0> enum.next
=> "30"
irb(main):001:0> class IPAddr
irb(main):002:1>   include Enumerable
irb(main):003:1> 
irb(main):004:1*   def initialize(ip_addr)
irb(main):005:2>     @ip_addr = ip_addr
irb(main):006:2>   end
irb(main):007:1> 
irb(main):008:1*   def each
irb(main):009:2>     return enum_for unless block_given?
irb(main):010:2> 
irb(main):011:2*     @ip_addr.split('.').each do |octet|
irb(main):012:3*       yield octet
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
=> :each
irb(main):016:0> 
irb(main):017:0* addr = IPAddr.new("192.10.20.30")
=> #<IPAddr:0x0055afc3901730 @ip_addr="192.10.20.30">
irb(main):018:0> enum = addr.each
=> #<Enumerator: #<IPAddr:0x0055afc3901730 @ip_addr="192.10.20.30">:each>
irb(main):019:0> enum.next
=> "192"
irb(main):020:0> enum.next
=> "10"
irb(main):021:0> enum.next
=> "20"
irb(main):022:0> enum.next
=> "30"

以下, 解説より抜粋.

  • Enumerable をインクルードした場合, each メソッドを実装する必要があり, ブロックが渡されない場合でも, Enumerator オブジェクトを返すようにして外部イテレータとしても使えるようにする
  • Enumerator オブジェクトを作成するメソッドは enum_for, または to_enum を利用する

フムフム.