毎日やったことを記録していく(2019/6/1 55日目)

今日やったこと

英語

TOEIC® L&R テスト 文法問題 でる1000問
  • 回答数:5問
iKnow
  • 新規:0個
  • 復習:5個
スタディサプリENGLISH
  • クイックワードクイズ:1サブセクション

開発

danime-nico-tools
  • fixturesの更新

その他

  • RubyのProc・lambdaについて調査

知ったこと

RubyのProc・lambdaに関して

RubyのProcとlambdaに関して理解不足なところがあったので調べ直して知識を整理してみた。

ブロック引数の書き方の違い
def a
  Proc.new { |b| puts b }
end

# 上記と下記は同じ
def a
  -> (b) { puts b }
end
ブロック引数の数の厳密性の違い

Procは渡した引数が多い場合は必要なもの以外は無視され、少ない場合は足りない箇所にはnilが入る。

# 渡す引数が多い場合
a = Proc.new { |b| b }
a.call(1,2) # => 1

# 渡す引数が少ない場合
a = Proc.new { |b,c| [b,c] }
a.call(1) # => [1,nil]

lambdaはブロック引数の数が異なるとArgumentErrorが発生する。

a = Proc.new { |b| puts b }
a.call(1,2) # => ArgumentError
returnやbreakを使用した際の違い

Procはメソッド内でcallするとcallされたメソッド自体の処理から抜ける。

def using_proc
  proc = Proc.new { return "proc"}
  a = proc.call
  'after ' + a
end
using_proc # =>"proc"

lambdaはブロック内の処理からのみ抜ける。

def using_lambda
  lambda = -> { return "lambda"}
  a = proc.call
  'after ' + a
end
using_lambda # =>"after lambda"
mapとかでよく見る&演算子

例えば下記のようなやつ。

[1,2,3].map(&b)

これは&で修飾されたオブジェクトをブロックとして評価する。

def b
  -> (c) { puts c }
end

[1,2,3].map(&b)

# 上記は下記と同じ
[1,2,3].map { |c| puts c }

あと&にメソッド名をシンボルで渡した場合。
まず、&にはProcやlambda以外にも、to_procを持つオブジェクトを渡せる。
デフォルトだとProc、lambda、Methodのオブジェクトがto_procを持つ。
また、シンボルもto_procを持っている。
リファレンスによると下記の通り。

self に対応する Proc オブジェクトを返します。
生成される Proc オブジェクトを呼びだす(Proc#call)と、 Proc#callの第一引数をレシーバとして、 self という名前のメソッドを 残りの引数を渡して呼びだします。

この&の挙動とSymbol#to_procによって、下記のようなよく見るコードが実現されている。

[1,2,3].map(&:to_s)

# Symbol#to_procが実行された際のイメージとしてはこんな感じ?
[1,2,3].map { |n| to_s_proc.call(n) }

# 最終的に下記を書いたことになる
[1,2,3].map { |n| n.to_s }
その他参考

methodを使ったテクはかなり有用そう。
ただ乱用すると可読性は落ちるかも?

qiita.com yuroyoro.hatenablog.com

感想等

この調子で

今日はずっと後回しにしていたProcに関する疑問を理解できたのでよかった。
この調子でコツコツタスクを消化していきたい。