T_Y_CODE

プログラミング学習記録

学習記録 4日目

4日目の学習記録をまとめていきます。
本日は外出予定があるため学習量は少なめです汗

学習計画

  • プロを目指す人のためのRuby入門 10章
  • リーダブルコード 9章

学習内容

プロを目指す人のためのRuby入門 10章

  • メソッド内で渡されたブロックを実行するにはyieldを用います。ブロックが渡されているか確認するにはblock_given?メソッドを使用します。
def greeting
  puts 'おはよう'
  if block_given?
    yield
  end
  puts 'こんばんは'
end

greeting
# => おはよう
#    こんばんは
greeting do
  puts 'こんにちは'
end
# => おはよう
#    こんにちは
#    こんばんは
  • yieldメソッドには引数を付けられます。引数は渡されたブロックの引数に対応しています。引数の個数の過不足には寛容で多い場合は切り捨て、少ない場合はnilになります。
def greeting
  puts 'おはよう'
  text = yield 'こんにちは', 12345
  puts text
  puts 'こんばんは'
end

greeting do |text| #第二引数がないため12345は格納されない。
  text * 2
end
# => おはよう
#    こんにちはこんにちは
#    こんばんは
  • メソッドの引数としてブロックを受け取れる。変数名には頭に&をつけること。以下はyieldと同意のcallメソッドを使用した例。
def greeting(&block)
  puts 'おはよう'
  if block.nil?
    text = block.call('こんにちは')
    puts text
  end
  puts 'こんばんは'
end

greeting do |text|
  text * 2
end
# => おはよう
#    こんにちはこんにちは
#    こんばんは
  • ブロックを引数として受け取るメリットは引数として受け取ったブロックを他のメソッドで使用出来ることにある。
def method_A(&block)
  method_B(&block)
end

def method_B(&block)
  puts block.call
  • またブロックに対してメソッドを呼び出し何かしらの操作を実行できる。arityメソッドはブロック引数の個数を返す。
def greeting(&block)
  puts 'おはよう'
  if block.arity == 1 # ブロック引数が1個の場合
    yield 'こんにちは'
  elsif block.arty == 2 # ブロック引数が2個の場合
    yield 'こんに', 'ちは'
  end
  puts 'こんばんは'
end

greeting do |text|
  text * 2
end
# => おはよう
#    こんにちはこんにちは
#    こんばんは
greeting do |text_1, text_2|
  text_1 * 2 + text_2 * 2
end
# => おはよう
#    こんにこんにちはちは
#    こんばんは
  • Procクラスはブロックをオブジェクト化するためのクラス。Proc.newで作成しオブジェクトからcallメソッドで呼び出す。
add_proc = Proc.new { |a, b| a + b }
add_proc.call(20, 30) # => 50
  • 引数はデフォルト指定可能。
add_proc = Proc.new { |a = 0, b = 0| a + b }
add_proc.call # => 0
add_proc.call(20) # => 20
add_proc.call(20, 30) # => 50
  • メソッドの引数で受け取ったブロックはメソッド実行時にオブジェクト化される。(=Procオブジェクトになっている) 先述のarityメソッドはProcのインスタンスメソッドである。
  • 上記よりメソッドの引数にブロックを渡す際、ブロックではなくProcオブジェクトを渡すことが可能。
  • Procオブジェクトをメソッドの引数として渡す場合ブロックとして渡すわけではないので渡す個数に制限はない。(ブロックは1つまで)
def greeting(proc_1, proc_2, proc_3)
  puts proc_1.call('おはよう')
  puts proc_2.call('こんにちは')
  puts proc_3.call('こんばんは')
end

shuffle_proc = Proc.new {  |text| text.chars.shuffle.join }
repeat_proc =  Proc.new { |text| text *  2 }
question_proc = Proc.new {  |text|  "#{text}?" }

greeting(shuffle_proc, repeat_proc, question_proc)
# => はおうよ
#    こんにちはこんにちは
#    こんばんは?
  • Procオブジェクトを作る方法としてラムダがある。ラムダとProc.newメソッドには2つの違いがある。
    • ラムダは引数の過不足があるとエラーが発生する。
    • Proc.newメソッドとラムダではreturn, breakの挙動が異なる。以下returnの例である。breakにした場合、Proc.newメソッドはエラーを吐く。ラムダはreturnと同じ挙動をする。
def proc_return
  f = Proc.new { |n| return n * 10 }
  ret = [1, 2, 3].map(&f)
  "ret: #{ret}"
end
def lambda_return
  f = -> n { return n * 10 }
  ret = [1, 2, 3].map(&f)
  "ret: #{ret}"
end
proc_return #=> ret: 10
lambda_return #=> ret: [10, 20, 30]
  • Procオブジェクトを実行する方法は以下の通りである。
add_proc = Proc.new { |a, b| a + b }

add_proc.call(10, 20) # => 30
add_proc.yield(10, 20) # => 30
add_proc.(10, 20) # => 30
add_proc[10, 20] # => 30
add_proc === [10, 20] # => 30
  • Procオブジェクトをブロックとして引数に渡したい場合は頭に&をつける。

リーダブルコード 9章

  • 以下のような変数は意味がない。
    • 複雑な式を分割していない。
    • datetime.datetime.now()で意味が通じるため説明変数に入れる意味がない。
    • 1度しか使用しておらず重複コードの削除になっていない。
now = datetime.datetime.now()
root_message.last_view_time = now
  • クラスのメンバ変数はミニグローバル変数と言える。クラスが巨大になればすべてのメンバ変数を把握するのは困難。したがってなるべくメンバ変数は減らした方が良い。
  • ミューダブルな変数が多いと値の追跡の難易度が上がる。変更のない変数は可能な限り定数にしてイミューダブルにするとトラブルが少なく済む。

本日の総括

  • 今まで暗記していた.map(&:)の意味が理解できてスッキリした。
  • 無駄な変数とは何なのかを学ぶことが出来た。