勉強部屋‎ > ‎Go 1‎ > ‎

演習6

演習5(3)のプログラムを実行する際,sttyコマンドを打込まなくていいように,プログラムを変更せよ.(ヒント:os/execパッケージのRun関数を用いると,プログラムから外部コマンドを実行することができる)

解答例

  1. package main
  2.  
  3. import (
  4.     "time"
  5.     "bufio"
  6.     "os"
  7.     "os/exec"
  8.     "./textbox"
  9. )
  10.   
  11. const text = "Go言語は、Googleが開発した新しいプログラミング言語です。"
  12.   
  13. // --- ProblemBox ---
  14. // 問題文を0.5秒ごとに1文字ずつ表示するデータ型.
  15. type ProblemBox struct {
  16.     *textbox.TextBox
  17.     text []rune
  18. }
  19.   
  20. // 位置,大きさ,表示する問題文を指定してProblemBoxを生成する.
  21. func New(x,y,w,h int, s string) (pb *ProblemBox) {
  22.     return &ProblemBox{textbox.New(x,y,w,h),[]rune(s)} 
  23. }
  24.   
  25. // 問題文を0.5秒ごとに表示する.
  26. func (pb *ProblemBox) Play() {
  27.     pb.Clear()
  28.     for i:= 0; i < len(pb.text); i++ {
  29.         pb.PutRune(pb.text[i])
  30.         time.Sleep(5e8)
  31.     }
  32.     pb.Puts("[Enter]")
  33. }
  34.   
  35. // --- ProblemBox end ---
  36.   
  37. func main() {
  38.     cmd := exec.Command("stty")
  39.     cmd.Args = []string {"stty", "-echo", "cbreak"}
  40.     cmd.Stdin = os.Stdin
  41.     cmd.Run()
  42.     defer func() {
  43.         cmd = exec.Command("stty")
  44.         cmd.Args = []string {"stty", "sane", "erase", "^H"}
  45.         cmd.Stdin = os.Stdin
  46.         cmd.Run()
  47.     }()
  48.   
  49.     textbox.Clear()
  50.   
  51.     textslice := []rune(text)
  52.   
  53.     t1 := New(3,3,70,4, text)
  54.     go t1.Play()
  55.   
  56.     t2 := textbox.New(3,8,70,4)
  57.     t3 := textbox.New(3,13,70,4)
  58.   
  59.     keyin := bufio.NewReader(os.Stdin)
  60.     for i:=0; i < len(textslice)+1; i++ {
  61.         c,_,_:= keyin.ReadRune()
  62.         if c == '\n' {
  63.             t2.Puts("[Enter]")
  64.         } else {
  65.             t2.PutRune(c)
  66.         }
  67.         if c == '\n' && i == len(textslice) {
  68.             t3.Puts("おめでとう! 成功です.")
  69.             break
  70.         } else if i < len(textslice) && c != textslice[i]  || c != '\n' && i == len(textslice) {
  71.         // 途中で間違えた || 最後に[Enter]以外の文字を押した
  72.             t3.Puts("残念でした.キーが違います.")
  73.             break
  74.         }
  75.     }
  76. }

解説

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と同じ動作
ċ
6-type.go
(2k)
Tetsuo Tanaka,
2012/04/29 19:39
Comments