while (token = lexer.read) != EOFをEnumeratorをつかってどうにかしたい
あたらしく研究室に入って(2度目)スクリプト言語の作り方って本が課題なのでやっていまして、そのときlexer作るんですが
while (token = lexer.read) != EOF ... end
的な書き方してて嫌な気持ちになったので他にまともな書き方がないか調べました.
どうしたいか
- while とかの中で代入はすきじゃないのでしたくない
- eachみたいにつかえる
- けど,任意の位置でreadできるようにしたい
- しかしメモリ使用量を抑えたいので一気に配列に突っ込むとかはしたくない
つまり下みたいにはしたくない
# ファイルひらいて一気に配列に突っ込む file = open(file_name).map { |f| f.strip } file.each do |f| ... end
どうしたか
Enumerator classを使いました.
例として以下の様なこと Enumerator
を使ってやってみました.
ファイルから1行ずつ読んでくる->読んできた1行になにかする(行番号をつける).
javaのLineNumberReader
みたいなやつ
class LineNumberReader def initialize(filename) @filename = filename end # nextがなかったらStopIterationをraiseする def read_line file.next end def peek_line file.peek end def has_next_line? !!file.peek rescue StopIteration false end # loopはStopIterationをrescueする def each loop { yield(read_line) } end private # each_line, with_indexは enumeratorを返すのでnextとかで逐次に取ってくるはず def file @file ||= open(@filename).each_line.with_index end end
LineNumberReader#file
がEnumerator
を返すようにしているので[メモリ使用量を抑えたいので一気に配列に突っ込むとかはしたくない]は解決出来てるはず
またLineNumberReader#read_line
を外から呼ぶようにすることで[任意の位置でreadできるようにしたい]も解決できる
reader = LineNumberReader.new('file.rb') p reader3.read_line ... p reader3.read_line if reader3.has_next_line?
またLineNumberReader#each
を作ってることで[eachみたいにつかえる]も解決
reader = LineNumberReader.new('file.rb') reader.each |f| ... end
while
使いたいときはloop
を使うと(実際eachで解消されてるけど)[while とかの中で代入はすきじゃないのでしたくない]も解決
reader = LineNumberReader.new('file.rb') loop p reader.read_line end
まとめ
ただのiteratorっぽいなにかだし,こんなことしてないで早く課題終わらせたほうが良さそう もっと賢い方法があればだれか教えてくれ!!

2週間でできる! スクリプト言語の作り方 (Software Design plus)
- 作者: 千葉滋
- 出版社/メーカー: 技術評論社
- 発売日: 2012/02/10
- メディア: 単行本(ソフトカバー)
- 購入: 11人 クリック: 318回
- この商品を含むブログ (18件) を見る