演習6
演習5(3)のプログラムを実行する際,sttyコマンドを打込まなくていいように,プログラムを変更せよ.(ヒント:os/execパッケージのRun関数を用いると,プログラムから外部コマンドを実行することができる)
解答例
解答例
- package main
- import (
- "time"
- "bufio"
- "os"
- "os/exec"
- "./textbox"
- )
- const text = "Go言語は、Googleが開発した新しいプログラミング言語です。"
- // --- ProblemBox ---
- // 問題文を0.5秒ごとに1文字ずつ表示するデータ型.
- type ProblemBox struct {
- *textbox.TextBox
- text []rune
- }
- // 位置,大きさ,表示する問題文を指定してProblemBoxを生成する.
- func New(x,y,w,h int, s string) (pb *ProblemBox) {
- return &ProblemBox{textbox.New(x,y,w,h),[]rune(s)}
- }
- // 問題文を0.5秒ごとに表示する.
- func (pb *ProblemBox) Play() {
- pb.Clear()
- for i:= 0; i < len(pb.text); i++ {
- pb.PutRune(pb.text[i])
- time.Sleep(5e8)
- }
- pb.Puts("[Enter]")
- }
- // --- ProblemBox end ---
- func main() {
- cmd := exec.Command("stty")
- cmd.Args = []string {"stty", "-echo", "cbreak"}
- cmd.Stdin = os.Stdin
- cmd.Run()
- defer func() {
- cmd = exec.Command("stty")
- cmd.Args = []string {"stty", "sane", "erase", "^H"}
- cmd.Stdin = os.Stdin
- cmd.Run()
- }()
- textbox.Clear()
- textslice := []rune(text)
- t1 := New(3,3,70,4, text)
- go t1.Play()
- t2 := textbox.New(3,8,70,4)
- t3 := textbox.New(3,13,70,4)
- keyin := bufio.NewReader(os.Stdin)
- for i:=0; i < len(textslice)+1; i++ {
- c,_,_:= keyin.ReadRune()
- if c == '\n' {
- t2.Puts("[Enter]")
- } else {
- t2.PutRune(c)
- }
- if c == '\n' && i == len(textslice) {
- t3.Puts("おめでとう! 成功です.")
- break
- } else if i < len(textslice) && c != textslice[i] || c != '\n' && i == len(textslice) {
- // 途中で間違えた || 最後に[Enter]以外の文字を押した
- t3.Puts("残念でした.キーが違います.")
- break
- }
- }
- }
解説
解説
os/execパッケージ
- os/execパッケージは,外部コマンドを実行するためのパッケージです.os.StartProcessをラップして,stdin,stdoutの再マップなどを容易にしています.
- 外部コマンドを実行するには,解答例の38行目から41行目のようにプログラムします.Command関数でCmd型のデータを生成し,そのフィールドに値をセットします.ArgsにコマンドとパラメータをセットしてRun()メソッドを呼び出すことで,そのコマンドを実行します.
- os/execパッケージの詳細は,Package exec(英語)を参照してください.
defer文
- defer文は,defer文を記述している関数自体がリターンするまで,指定した関数の実行を先延ばしします.
- 解答例の42行目から47行目の関数リテラルは,main()関数がリターンする直前(すなわち,プログラムの終了直前)に実行されます.
- 関数内のどの経路を通ってリターンするかに関わらず,ファイルのクローズなど,開放しなければならないリソースなどを処理するのに有効です.
- defer文の詳細については,言語仕様,実践Go言語を参照してください.
プログラムの動作(main)
- 38行目~41行目:コマンド stty cbreak -echo を実行.
- 42行目~47行目:コマンド stty sane erase ^H をmain関数の最後に実行.
- 49行目以降:演習5と同じ動作