せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】rescueの優先順位、並列実行、メソッドのブロック、aliasキーワードを使った既存メソッドの拡張

 
この本を読んでいます。

プログラミング言語 Ruby

プログラミング言語 Ruby


 
以下、気がついたことなど。

 

rescue、代入演算子、ifの優先順位

rescue演算子は代入演算子よりも優先順位が高い

# メソッドが例外を起こしたらy=0
y = factorical(x) rescue 0

 
優先順位が高い、というのは「先に評価される」という意味。
y = (factorical(x) rescue 0)
こういうイメージ。
 
「ifは代入演算子よりも優先順位が低い」とは
(y=5) if a == 0
こういうイメージ。
ifは修飾子であり演算子ではないので(y=5)が最初に実行されることはない。
if修飾子は、後ろを先に評価する。


 

並列実行、メソッドのブロック

Thread.newでスレッドを生成できる。

本のコードを元に、スレッドあり/なしで2メソッド書いてみる。

def readfiles_threads(filenames)
  threads = filenames.map do |f|
    Thread.new do 
      File.read(f)
      p "start + #{f}"
    end
  end
  p "main thread readfiles_threads"
  threads.map{ |t| t.value }
  p "after"
end

def readfiles(filenames)
  files = []
  filenames.each do |f|
    files << File.read(f)
    p "start + #{f}"
  end
  p "main thread"
end

dir = File.dirname(__FILE__)
filenames=[
dir+"/test1.txt",・・・
dir+"/test7.txt",
]
readfiles_threads(filenames)
p "---------------------"
readfiles(filenames)

 
■実行結果

"main thread readfiles_threads"
"start + C:/test/test4.txt"
"start + C:/test/test2.txt"
"start + C:/test/test1.txt"
"start + C:/test/test3.txt"
"start + C:/test/test5.txt"
"start + C:/test/test6.txt"
"start + C:/test/test7.txt"
"after"
"---------------------"
"start + C:/test/test1.txt"
"start + C:/test/test2.txt"
"start + C:/test/test3.txt"
"start + C:/test/test4.txt"
"start + C:/test/test5.txt"
"start + C:/test/test6.txt"
"start + C:/test/test7.txt"
"main thread readfiles"

ここから分かることは、、

Thread.new でスレッドを作成して並列処理を行うため、
mainスレッドのpメソッドはイテレーター終了後に実施されるわけではない
 →"main thread readfiles_threads"はイテレーターよりも先に表示されている
 
Thread.valueでスレッド終了後までメソッドがロックできる
 →"after"は必ずイテレーター終了後に表示される
 
並列処理をしていない場合は、
"main thread readfiles"は当然 イテレーターの後に表示される

 
 

aliasを使ったよくあるイディオム

メソッドは複数回定義されると上書きされる

def hello
  p "hello"
end
def hello
  p "twice"
end
hello

■実行結果

"twice"

 
この性質を利用して、
既存のメソッドに追加するときによくあるイディオム。

def hello
  p "hello"
end
alias original_hello hello 

def hello
  original_hello
  p "twice"
end
hello
original_hello

■実行結果

"hello"
"twice"
"hello"

 
aliasで既存のメソッドを別名にて退避させておいて、
既存のメソッドを上書く。
なるほど。


 
あと、returnを明示しなくても複数の返り値を設定する方法があったので、
以前のブログを修正しました