無限大な夢のあと

テニスとアニメが大好きな厨二病SEのブログ

「プログラマ脳を鍛える数学パズル」でGolang入門 2問目(数列 の 四則演算) 文法解説編

普段はJavaプログラマな私が「プログラマ脳を鍛える数学パズル」の問題を解いていく中で、Golangに入門していく記事。

コードを解くに当たって、参考にしたページなども合わせて記載してみる。
ちなみにGoのバージョンは1.6。


1問目の解答編はこちら。
「プログラマ脳を鍛える数学パズル」でGolang入門 1問目(10進数で回文) 解答編 - スーツとギークのはざまで


2問目の解答編はこちら。
「プログラマ脳を鍛える数学パズル」でGolang入門 2問目(数列 の 四則演算) 解答編 - スーツとギークのはざまで



※本記事は主に以下の記事を参考に記載されています。
Scanner周りは記事の中身から抜粋させて頂いています。
お気楽 Go 言語プログラミング入門




1.構造体について
まだ自分の言葉で説明できるほど理解が進んでいないので、記事へのリンクを記載します。

概要のみ押さえたい方はこちら。
dev.classmethod.jp

私のようにC言語等の経験がほぼない方はこちら。
お気楽 Go 言語プログラミング入門

Javaenumっぽいイメージだけど、厳密には違う(enumに比べて機能が足りない)みたい。
oinume.hatenablog.com
mattn.kaoriya.net


2.Scannerクラスについて
Go 言語のパッケージ text/scanner には字句解析を行うScannerが用意されている。
Scanner は UTF-8エンコードされたテキストを Go 言語の文法に従って解析する。
Sccanner の使い方は簡単。基本的には次に示す 3 つの関数 (メソッド) で字句解析を行う。

func (s *Scanner) Init(src io.Reader) *Scanner
func (s *Scanner) Scan() rune
func (s *Scanner) TokenText() string

Scanner は字句解析を制御するための構造体。
メソッド Init は Scanner を初期化します。
ソース (テキストファイル) として io.Reader を渡します。
解答では、strings.NewReaderメソッドを引数に渡している。
qiita.com

メソッド Scan はソースから空白文字と Go 言語のコメントを読み飛ばしてトークンを切り出す。
返り値の型 rune は int32 の別名で、UTF-8文字コードを表す。
Scan はトークンの種別を負の整数で返し、+ や * などの記号はその文字コードを返す。
切り分けたトークンはメソッド TokenText で取り出すことができる。

リスト : トークンの種別

const (
    EOF = -(iota + 1)
    Ident
    Int
    Float
    Char
    String
    RawString
    Comment
)

EOF はファイルの終了を表す。Ident は識別子、Int は整数、Float は実数、Char は文字 ('a', 'b' など)、String は文字列 ("foo", "bar" など) を表す。



3.Scannerクラスでのサンプル

それでは実際に scanner を使ってみよう。

package main

 import (
    "fmt"
    "os"
    "text/scanner"
)

func main() {
    var s scanner.Scanner
    s.Init(os.Stdin)
    for {
        fmt.Print("> ")
        x := s.Scan()
        fmt.Println(x, s.TokenText())
    }
}

変数 s に Scanner を用意。
s.Init(os.Stdin) で Scanner を初期化し、次の for ループで標準入力からのテキストを s.Scan() で字句解析する。
TokenText は Scan を実行したあと有効で、そのとき切り分けたトークンを文字列にして返す。
Scanner の場合、for や if も識別子 (Ident) として認識される。

実際には、次のような構造体とメソッドを定義して、切り分けたトークンを保存しておくと便利。

リスト : 字句解析

type Lex struct {
    scanner.Scanner
    Token rune
}

func (lex *Lex) getToken() {
    lex.Token = lex.Scan()
}

構造体 Lex は Scanner を埋め込み、切り分けたトークンをフィールド変数 Token に格納します。メソッド getToken は Scan を呼び出してトークンを切り出し、その結果を Token にセットします。

改訂2版 基礎からわかる Go言語

改訂2版 基礎からわかる Go言語

Go言語によるWebアプリケーション開発

Go言語によるWebアプリケーション開発

スターティングGo言語 (CodeZine BOOKS)

スターティングGo言語 (CodeZine BOOKS)