わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

forの中で変数に代入すると

 学生からメールが来ました.
 研究で作成しているRubyスクリプトが,うまく動かないというのです.
 明日じっくり読んで返信しますと,短いメールを送り,次の日にじっくり読んだところ,10分ほどで原因が分かりました.エラーを含む何行かのコードが,1文で表せることにも気づいて,詳しく書いたメールを送りました.
 エラーの原因は,値が代入されていない変数を参照した,というやつです.確認コードを:

#!/usr/bin/env ruby

a = 0
for i in 1...10
  a = i     # 外の変数aの値を変える
  b = i * 2 # ここで最初にbに代入されるとき,bの有効範囲はブロック内
end
puts a      # 「9」を出力
puts b      # bが参照できないのでエラー

 ふだん自分はRubyでfor文*1を書くことはほとんどありませんが,学生のバグを再現しようと思い,使ってみました.
 実行すると…あれれ,エラーが出ません.「9」と「18」が出力されました.
 上記のコメントの「ここで最初にbに代入されるとき,bの有効範囲はブロック内」が間違いなのでした.for文は,endで終わりますが,ブロックを構成しません.http://miyamae.github.io/rubydoc-ja/2.4.0/#!/doc/spec=2fcontrol.html?forにも,「do ... endまたは{ }による ブロックは新しいローカル変数の有効範囲を導入するのに対し、 for文はローカル変数のスコープに影響を及ぼさない」と書いてありました.
 エラーを発生させるには,次のようにしないといけません.

#!/usr/bin/env ruby

a = 0
10.times do |i|
  a = i     # 外の変数aの値を変える
  b = i * 2 # ここで最初にbに代入されるとき,bの有効範囲はブロック内
end
puts a      # 「9」を出力
puts b      # bが参照できないのでエラー

 実行すると,「undefined local variable or method `b' for main:Object (NameError)」というエラーメッセージが出ました.

*1:Moodleで回収したzipファイルを展開して,数十人の学生の答案(オンラインテキスト)に対し,採点しやすいよう,学生番号やファイル名をヘッダとフッタを付けてから,結合して一つのファイルにするときには,zshのforコマンドを活用しています.