読者です 読者をやめる 読者になる 読者になる

woshidan's loose leaf

ぼんやり勉強しています。

IO#readlineは$_変数に実行結果を格納しないの?

Effective Ruby Ruby

Effective RubyのKernel#readlineメソッドあたりの記述

では、ここでは何が行われているのだろうか。このコードは、readlineメソッドから始まっている。より厳密に言えば、Kernel#readlineメソッドだ(項目6ではたとえばここでRubyがKernelモジュールのreadlineメソッドを選んでいる仕組みを掘り下げるつもりだ)。このバージョンのreadlineは、IOクラスのreadlineと少し異なる。おそらく読者は、readlineが標準入力から行を読み出して返す関数だという事を推測できるだろう。微妙な違いというのは、このバージョンが入力行を $_ 変数にも格納する事だ(Kernel#getsも同じ事を行うが、EOFマーカーに達しても例外を発生しない)。同様に、Kernel#printは、引数無しで呼び出されたときには、 $_ 変数の内容を標準入力に書き込む

「 『$_変数が現在のスコープで何でも最後に実行されたメソッドの返り値が書き込まれる(Rubyの仕組みとして)』という覚え方をしたので、Kernel#readlineメソッドもIO#readlineメソッドもどっちも出力結果を返すのだから、どっちも次の行の$_変数でその結果を取得できるような気がしてる」

twitterで呟こうとして、デザイナの人ともつながってるし、なんか怖い人みたいだ、となったので、こっちで検証してみる。

参考

Rubyのバージョンは

ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-darwin13.0]

IO#readlineを使った場合

test.txt

1
2
3
4
5
6
7
8
9
10
f = File.new("./test.txt")
begin
  while f.readline
    puts $_ # インタプリタから$_を呼び出す時は_でいいが、Rubyのコードからだと$が要る
  end
rescue EOFError
ensure
  f.close
end

実行結果

1
2
3
4
5
6
7
8
9
10

Kernel#readlineを使った場合

readline.rb

while readline
  puts $_
end

実行結果

$ ruby -n readline.rb
# 1 標準入力。最初の標準入力はどうもうまく動いてない...(汗)
# 2
2
# 3
3
# 4
4
# 5
5
# 6
6
# 7
7
# 8
8
# 9
9
# 10
10

やっぱ両方$_に書き込めてる気がする。

どっちかというと、その何も入力してない場合、Kernelクラスのインスタンス変数だったら$_変数にアクセスできる、みたいな雰囲気がしたけど、そこまで追わない。

まあ読みにくいので使わない方が良いので、これでおしまい。