Last active
August 29, 2015 13:57
-
-
Save Jxck/9551539 to your computer and use it in GitHub Desktop.
Revisions
-
Jxck revised this gist
Mar 16, 2014 . 2 changed files with 82 additions and 45 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -160,7 +160,7 @@ Task{} はインスタンスの実体を返し、 ```go func main() { // new 的なこと task := &Task{ Id: 1, Detail: "buy the milk", @@ -174,7 +174,7 @@ func main() { ```go func main() { // bool のゼロ値は false なので Done は省略可 task := &Task{ Id: 1, Detail: "buy the milk", @@ -317,13 +317,13 @@ func main() { ```go func IndexHandler(w http.ResponseWriter, r *http.Request) { // heredoc html := ` <!DOCTYPE html> <title>tasks</title> <h1>here is your <a href="%s">tasks</a></h1> ` fmt.Fprintf(w, html, "/tasks") } func main() { @@ -366,7 +366,7 @@ func TasksHandler(w http.ResponseWriter, r *http.Request) { tasks.Add(NewTask(1, "buy the milk")) tasks.Add(NewTask(2, "eat the pie")) // こういうのがあっても大丈夫 tasks.Add(NewTask(3, "<b>go to the bank</b>")) html := ` @@ -380,7 +380,7 @@ func TasksHandler(w http.ResponseWriter, r *http.Request) { </ul> ` // 第二引数がエラーを返すイディオム TasksList, err := template.New("tasklist").Parse(html) if err != nil { log.Fatal(err) @@ -420,9 +420,9 @@ func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { } func main() { // snip http.HandleFunc("/tasks", TasksHandler(tasks)) // snip } ``` @@ -436,7 +436,7 @@ Tasks を [encoding/json](http://golang.org/pkg/encoding/json/) を用いてシ // b, err := json.Marshal(tasks) // インデントなし b, err := json.MarshalIndent(tasks, "", " ") // プレフィックス、インデントあり if err != nil { log.Fatal(err) } log.Println(string(b)) // 文字列化 ``` @@ -478,6 +478,27 @@ type Tasks struct { 送信は fmt.Fprint() で良いでしょう。 Content-Type とか細かいことは気にしない! ## おまけ 当日時間があったので Slice の内部構造について解説し、 それを利用して Tasks.Del() を実装した。 ```go func (tasks *Tasks) Del(id int) { for i, task := range tasks.Tasks { if task.Id == id { copy(tasks.Tasks[i:], tasks.Tasks[i+1:]) tasks.Tasks[len(tasks.Tasks)-1] = nil tasks.Tasks = tasks.Tasks[:len(tasks.Tasks)-1] break } } } ``` 詳細は、この辺を参照してほしい。 https://code.google.com/p/go-wiki/wiki/SliceTricks ## 終わり @@ -486,7 +507,7 @@ Content-Type とか細かいことは気にしない! 話せなかったこと - interface - new() - channel, goroutine - module 分割 - その他たくさん @@ -535,7 +556,7 @@ Content-Type とか細かいことは気にしない! ```go func (task *Task) Edit(detail string) { ttask.Detail = detail } ``` This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -12,23 +12,6 @@ func init() { log.SetFlags(log.Lshortfile) } type Task struct { Id int `json:"id"` Detail string `json:"detail"` @@ -39,36 +22,67 @@ func NewTask(id int, detail string) *Task { task := &Task{ Id: id, Detail: detail, } return task } func (task *Task) Finish() { task.Done = true } func (task *Task) String() string { var status string if task.Done { status = "done" } else { status = "not yet" } str := fmt.Sprintf( "%d) %s (%s)", task.Id, task.Detail, status) return str } func (task *Task) Edit(detail string) { task.Detail = detail } type Tasks struct { Owner string `json:"owner"` Tasks []*Task `json:"tasks"` } func NewTasks(owner string) *Tasks { tasks := &Tasks{ Owner: owner, Tasks: make([]*Task, 0, 16), } return tasks } func (tasks *Tasks) Add(task *Task) { tasks.Tasks = append(tasks.Tasks, task) } func (tasks *Tasks) Del(id int) { for i, task := range tasks.Tasks { if task.Id == id { copy(tasks.Tasks[i:], tasks.Tasks[i+1:]) tasks.Tasks[len(tasks.Tasks)-1] = nil tasks.Tasks = tasks.Tasks[:len(tasks.Tasks)-1] break } } } func IndexHandler(w http.ResponseWriter, r *http.Request) { // heredoc html := ` <!DOCTYPE html> <title>tasks</title> <h1>here is your <a href="%s">tasks</a></h1> ` fmt.Fprintf(w, html, "/tasks") } func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { @@ -78,14 +92,16 @@ func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { <h1>{{.Owner}}'s tasks</h1> <ul> {{range .Tasks}} <li>{{.}}</li> {{end}} </ul> ` TasksList, err := template.New("tasklist").Parse(html) if err != nil { log.Fatal(err) } return func(w http.ResponseWriter, r *http.Request) { TasksList.Execute(w, tasks) } @@ -97,15 +113,15 @@ func TasksJSONHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) log.Fatal(err) } return func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, string(b)) } } func main() { tasks := NewTasks("Jxck") tasks.Add(NewTask(1, "buy the milk")) tasks.Add(NewTask(2, "eat the pie")) tasks.Add(NewTask(3, "<b>go to the bank</b>")) http.HandleFunc("/", IndexHandler) http.HandleFunc("/tasks", TasksHandler(tasks)) -
Jxck revised this gist
Mar 15, 2014 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -302,7 +302,7 @@ func main() { tasks.Add(NewTask(2, "eat the pie")) tasks.Add(NewTask(3, "go to the bank")) log.Println(tasks.Owner) for i, task := range tasks.Tasks { log.Printf("%d %s", i, task) } @@ -545,7 +545,6 @@ func (task *Task) Edit(detail string) { func NewTasks(owner string) *Tasks { tasks := &Tasks{ Owner: owner, } return tasks } -
Jxck revised this gist
Mar 15, 2014 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -78,7 +78,7 @@ $ godoc fmt $ godoc -http=":4000" & ``` [http://localhost:4000](http://localhost:4000) で起動される。 ## Print Debug @@ -339,7 +339,7 @@ fmt.Fprintf は、第一引数に Writer を受け、第二引数をそこに書 ## 課題3 TasksHandler を作成し、とりあえず main でやっていたことを移して、 [http://localhost:3000/tasks](http://localhost:3000/tasks) でタスクをリスト表示する。 実装は、 fmt.Fprintf を用いて ResponseWriter にガンガン書き込む感じで良い。 @@ -473,7 +473,7 @@ type Tasks struct { ## 課題4 [http://localhost:3000/tasks.json](http://localhost:3000/tasks.json) でタスクを JSON で取得できる API を作成するため TasksJSONHandler を作成し、サーバに登録しなさい。 送信は fmt.Fprint() で良いでしょう。 Content-Type とか細かいことは気にしない! -
Jxck revised this gist
Mar 15, 2014 . 2 changed files with 41 additions and 22 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,20 @@ # Go Kyoto (Go勉強会 そうだ京都、行こう) ## About ### 実施概要 - 2014/3/15 (土) 14:00 - http://www.zusaar.com/event/4367004 ### 前提 - 多言語で基本的なプログラミング知識(Web 系?) がある。 - Go のインストール、開発環境(エディタとか)の準備済み。 - http://go-tour-jp.appspot.com/ を一通り(24, 48, 60, 69, 70 は飛ばしてよし) ## タスク管理ツール - タスク管理ツール的なものを作りながら、 Go のひと通りの機能を触る。 @@ -8,7 +23,7 @@ - 標準モジュールでできることのみ。 - 環境構築は終わっている前提。 - 1 ファイルで完結させる構成(main.go のみ) - 時間がないので色々省略している部分は最後にリンクを。 - 時間があまったらテストの話。 @@ -63,14 +78,14 @@ $ godoc fmt $ godoc -http=":4000" & ``` http://localhost:4000 で起動される。 ## Print Debug fmt.Print() が stdout, log.Print() が stderr に出力。 init() は初期化処理が記述でき、 log.SetFlags() でフォーマットが変えられる。 フォーマットは http://golang.org/pkg/log/#pkg-constants 参照 ```go import ( @@ -208,7 +223,7 @@ func (task *Task) Finish() { // 引数,戻り値無し ## 課題1 Task.Detail を引数で受け取った detail string でまるっと上書きする Edit メソッドを実装しなさい。 ## IF @@ -296,17 +311,18 @@ func main() { ## HTTP タスク内容を [net/http](http://golang.org/pkg/net/http) で公開するサーバを作成。 まず index ページとしてリンクのみを表示するハンドラを作成。 ハンドラを登録したサーバを port 3000 で起動。 ```go func IndexHandler(w http.ResponseWriter, r *http.Request) { // heredoc html := ` <!DOCTYPE html> <title>tasks</title> <h1>here is your <a href="/tasks">tasks</a></h1> ` fmt.Fprintf(w, html) } @@ -323,7 +339,7 @@ fmt.Fprintf は、第一引数に Writer を受け、第二引数をそこに書 ## 課題3 TasksHandler を作成し、とりあえず main でやっていたことを移して、 http://localhost:3000/tasks でタスクをリスト表示する。 実装は、 fmt.Fprintf を用いて ResponseWriter にガンガン書き込む感じで良い。 @@ -353,7 +369,8 @@ func TasksHandler(w http.ResponseWriter, r *http.Request) { // こういうのがあっても大丈夫 tasks.Add(NewTask(3, "<b>go to the bank</b>")) html := ` <!DOCTYPE html> <title>tasks</title> <h1>{{.Owner}}'s tasks</h1> <ul> @@ -456,7 +473,7 @@ type Tasks struct { ## 課題4 http://localhost:3000/tasks.json でタスクを JSON で取得できる API を作成するため TasksJSONHandler を作成し、サーバに登録しなさい。 送信は fmt.Fprint() で良いでしょう。 Content-Type とか細かいことは気にしない! @@ -479,10 +496,10 @@ Content-Type とか細かいことは気にしない! ### Documents - 言語仕様: http://golang.org/ref/spec - Effective Go: http://golang.org/doc/effective_go.html - パッケージドキュメント: http://golang.org/pkg - 公式ブログ(細かい機能解説などがある): http://blog.golang.org/ ### Resources This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -63,15 +63,17 @@ func (task Task) String() string { // 引数なし,戻り値あり } func IndexHandler(w http.ResponseWriter, r *http.Request) { html := ` <!DOCTYPE html> <title>tasks</title> <h1>here is your <a href="/tasks">tasks</a></h1> ` fmt.Fprintf(w, html) } func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { html := ` <!DOCTYPE html> <title>tasks</title> <h1>{{.Owner}}'s tasks</h1> <ul> -
Jxck revised this gist
Mar 15, 2014 . 1 changed file with 106 additions and 74 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,13 +5,18 @@ - タスク管理ツール的なものを作りながら、 Go のひと通りの機能を触る。 - Go をひと通り触るのが目的なので、ツール自体の機能とかはこだわらない。 - 他の言語での経験がある方が対象なので、プログラミング言語の基本的な話は省略。 - 標準モジュールでできることのみ。 - 環境構築は終わっている前提。 - 1 ファイルで完結させる構成(main.go のみ) - 時間がないので並行系の話はなくなく削る。 - 時間があまったらテストの話。 # Hands On ハンズオン形式で進め、途中で課題をいくつか実施。 ## main main() がいわゆる main 文。 @@ -22,38 +27,58 @@ package main import ( "fmt" ) func main() { fmt.Println("Go Kyoto!") } ``` フォーマット ```sh $ go fmt main.go ``` 実行 ```sh $ go run main.go Go Kyoto! ``` フォーマッタは、コミットフックやエディタで保存時にやるのを推奨。 ## Document 電波がなくても、標準モジュールと自分が書いたモジュールのドキュメントはローカルで見られる。 ```sh $ godoc fmt ``` サーバも内蔵されている。 ```sh $ godoc -http=":4000" & ``` [http://localhost:4000] で起動される。 ## Print Debug fmt.Print() が stdout, log.Print() が stderr に出力。 init() は初期化処理が記述でき、 log.SetFlags() でフォーマットが変えられる。 フォーマットは [http://golang.org/pkg/log/#pkg-constants] 参照 ```go import ( "fmt" "log" ) func init() { // 初期化処理 // 日付ではなく行番号になるのでおすすめ log.SetFlags(log.Lshortfile) } @@ -66,7 +91,7 @@ func main() { } ``` ## Variables 定義は変数名が先、型が後。 @@ -90,7 +115,7 @@ func main() { } ``` 暗黙的型宣言 ```go func main() { @@ -103,7 +128,7 @@ func main() { ## Struct 構造体。(オブジェクト的なもの) メンバは、大文字が Public、小文字が Private ```go @@ -130,10 +155,23 @@ func main() { } ``` インスタンス生成時に、値を明示的に指定しなかったら暗黙的に各型に応じた初期値が使用される。これを [ゼロ値](http://golang.org/ref/spec#The_zero_value) という。 ```go func main() { // bool のゼロ値は false なので Done は省略可 task := &Task{ Id: 1, Detail: "buy the milk", } log.Printf("%+v", task) // 見やすい } ``` ## Function Task を New する関数は NewTask という関数名にするのが通例。 (コンストラクタ相当) ```go func NewTask(id int, detail string) *Task { @@ -153,10 +191,10 @@ func main() { ## Method struct にはメソッドが定義できる。 レシーバが、実体のものとポインタのもので定義方法が違う。 String() は、表示などで文字列化するときに使われる Stringer というインタフェースのメソッド。(toString() とか相当) ```go func (task Task) String() string { // 引数なし,戻り値あり @@ -174,11 +212,11 @@ Task.Detail を引数で受け取った detail でまるっと上書きする Ed ## IF 中括弧はいらない。 三項演算子はない。 ```go func (task Task) String() string { var status string if task.Done { status = "done" @@ -191,8 +229,9 @@ func (task Task) String() string { // 引数なし,戻り値あり ## Slice 可変長な配列だと思えば良い。 追加には組み込み関数の append() を使用する。 (追加結果を返すことに注意) ```Go func main() { @@ -206,54 +245,28 @@ func main() { ``` 実際は、固定長配列のビューとなっている。 固定長な配列は別にある。 今回は make() を用いた初期化は省略。 詳細は http://blog.golang.org/go-maps-in-action を参照のこと。 ## For 繰り返しを表現する方法は for のみ。While などない。 range を用いてイテレーションが可能、インデックスと要素を返す。 (イテレータ相当) ```go for i, task := range tasks { log.Printf("%d %s", i, task) } // 宣言して使わない変数は許されないので // 使わないなら _ で宣言する for _, task := range tasks { log.Printf("%s", task) } ``` ## 課題2 Tasks を以下のように定義し、 NewTasks 関数と Add メソッドを実装しなさい。 @@ -303,13 +316,14 @@ func main() { } ``` [http.ResponseWriter](http://golang.org/pkg/net/http/#ResponseWriter) は Writer というインタフェースを実装しており、書き込み可能なオブジェクト。 fmt.Fprintf は、第一引数に Writer を受け、第二引数をそこに書き込む。 今回は使用していないが、 [*http.Request](http://golang.org/pkg/net/http/#Request) の中にはリクエストに関する情報が全て入っている。 ## 課題3 TasksHandler を作成し、とりあえず main でやっていたことを移して、 [http://localhost:3000/tasks] でタスクをリスト表示する。 実装は、 fmt.Fprintf を用いて ResponseWriter にガンガン書き込む感じで良い。 @@ -328,8 +342,7 @@ TasksHandler を作成し、とりあえず main でやっていたことを移 ## Template 標準で [text/template](http://golang.org/pkg/text/template/) と [html/template](http://golang.org/pkg/html/template/) があり、インタフェースは基本的に同じだが、 html/template の方はエスケープ処理などを標準で行ってくれるため Web 用途ではこちらを使う。 ```go func TasksHandler(w http.ResponseWriter, r *http.Request) { @@ -359,14 +372,15 @@ func TasksHandler(w http.ResponseWriter, r *http.Request) { } ``` Go の関数は多値を返せる、 error が発生する場合は、引数の最後に返すのがイディオム。 実際はこれを処理したり、呼び出し元に返したりするが今回は log.Fatal() でプロセスを落としている。 (今回は扱わないが、 panic/recover というエラーの制御方法もある http://blog.golang.org/defer-panic-and-recover) ## Closure クロージャを用いて関数を返す関数にする。(Go では関数は First Class) tasks を受け取り [http.Handler](http://golang.org/pkg/net/http/#Handler) を返す関数にし、 main() から tasks を渡せるようにする。 ```go func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { @@ -397,9 +411,9 @@ func main() { ## JSON Tasks を [encoding/json](http://golang.org/pkg/encoding/json/) を用いてシリアライズする。 基本的には Marshal() か MarshalIndent() に渡すだけ。 戻り値は []byte というバイトのスライスなので、文字列にする場合は変換が必要。 ```go // b, err := json.Marshal(tasks) // インデントなし @@ -435,22 +449,40 @@ type Task struct { ```go type Tasks struct { Owner string `json:"owner"` Tasks []*Task `json:"tasks"` } ``` ## 課題4 [http://localhost:3000/tasks.json] でタスクを JSON で取得できる API を作成するため TasksJSONHandler を作成し、サーバに登録しなさい。 送信は fmt.Fprint() で良いでしょう。 Content-Type とか細かいことは気にしない! ## 終わり 時間が余ったら、 tasks のモジュール分けとテストを書きます。 話せなかったこと - interface - make(), new() - channel, goroutine - module 分割 - その他たくさん # 参考資料 ### Documents - 言語仕様: [http://golang.org/ref/spec] - Effective Go: [http://golang.org/doc/effective_go.html] - パッケージドキュメント: [http://golang.org/pkg] - 公式ブログ(細かい機能解説などがある): [http://blog.golang.org/] ### Resources @@ -480,7 +512,7 @@ content-type とか細かいことは気にしない! - etc ## 解答例 ### 課題1 -
Jxck revised this gist
Mar 15, 2014 . 1 changed file with 0 additions and 27 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,27 +0,0 @@ -
Jxck revised this gist
Mar 14, 2014 . 1 changed file with 30 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,7 +10,6 @@ - 1 ファイルで完結させる構成(main.go のみ) - 時間がないので並行系の話はなくなく削ります。 # Hands On ## main @@ -31,13 +30,13 @@ func main() { ``` ```sh $ go run main.go Go Kyoto! ``` ```sh $ go build main.go $ ./main Go Kyoto! @@ -119,7 +118,7 @@ type Task struct { Task{} はインスタンスの実体を返し、 &Task{} はポインタを返す。 ```go func main() { // new 的なこと task := &Task{ @@ -178,7 +177,7 @@ Task.Detail を引数で受け取った detail でまるっと上書きする Ed 中括弧などいらない。 三項演算子はない。 ```go func (task Task) String() string { // 引数なし,戻り値あり var status string if task.Done { @@ -230,7 +229,7 @@ range はイテレータの役割を果たし、インデックスと要素を タスクをまとめる struct を定義してみる。 ```go type Tasks struct { Owner string Tasks []*Task @@ -483,9 +482,33 @@ content-type とか細かいことは気にしない! ## 回答 ### 課題1 ```go func (task *Task) Edit(detail string) { task.Detail = detail } ``` ### 課題2 ```go func NewTasks(owner string) *Tasks { tasks := &Tasks{ Owner: owner, Tasks: []*Task{}, } return tasks } func (tasks *Tasks) Add(task *Task) { tasks.Tasks = append(tasks.Tasks, task) } ``` ### 課題3 ```go func TasksHandler(w http.ResponseWriter, r *http.Request) { tasks := NewTasks("Jxck") tasks.Add(NewTask(1, "buy the milk")) -
Jxck revised this gist
Mar 14, 2014 . 2 changed files with 0 additions and 25 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,25 +0,0 @@ File renamed without changes. -
Jxck revised this gist
Mar 14, 2014 . 3 changed files with 604 additions and 71 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1 +1,522 @@ # Go Kyoto (Go勉強会 そうだ京都、行こう) ## タスク管理ツール - タスク管理ツール的なものを作りながら、 Go のひと通りの機能を触る。 - Go をひと通り触るのが目的なので、ツール自体の機能とかはこだわらない。 - 他の言語での経験がある方が対象なので、プログラミング言語の基本的な話は省略。 - 標準モジュールでできることしかやらない。 - 環境構築は終わっている前提。 - 1 ファイルで完結させる構成(main.go のみ) - 時間がないので並行系の話はなくなく削ります。 # Hands On ## main main() がいわゆる main 文。 main() は main パッケージにのみ作成可能。 ```go package main import ( "fmt" ) func main() { fmt.Println("Go Kyoto!") } ``` ``` $ go run main.go Go Kyoto! ``` ``` $ go build main.go $ ./main Go Kyoto! ``` ## プリントデバッグ Print は、 fmt が stdout, log が stderr に出力。 init() は初期化処理が記述でき、 log.SetFlags でフォーマットが変えられる。 ```go import ( "fmt" "log" ) func init() { // 日付ではなく行番号になるのでおすすめ log.SetFlags(log.Lshortfile) } func main() { fmt.Println("Go Kyoto!") fmt.Printf("%v", "Go Kyoto!\n") log.Println("Go Kyoto!") log.Printf("%v", "Go Kyoto!\n") } ``` ## 変数定義 定義は変数名が先、型が後。 ```go func main() { var id int = 1 var detail string = "buy the milk" var done bool = false log.Println(id, detail, done) } ``` ```go func main() { var ( id int = 1 detail string = "buy the milk" done bool = false ) log.Println(id, detail, done) } ``` 暗黙的宣言 ```go func main() { id := 1 detail := "buy the milk" done := false log.Println(id, detail, done) } ``` ## Struct 構造体。オブジェクトのようなもの。 メンバは、大文字が Public、小文字が Private ```go type Task struct { Id int Detail string Done bool } ``` インスタンスの生成。 Task{} はインスタンスの実体を返し、 &Task{} はポインタを返す。 ``` func main() { // new 的なこと task := &Task{ Id: 1, Detail: "buy the milk", Done: false, } log.Printf("%+v", task) // 見やすい } ``` ## Function Task を New する関数は NewTask という関数名にするのが通例。 (いわゆるコンストラクタの位置付け) ```go func NewTask(id int, detail string) *Task { task := &Task{ Id: id, Detail: detail, Done: false, } return task } func main() { task := NewTask(1, "buy the milk") log.Printf("%+v", task) } ``` ## Method struct にはメソッドがつけられる。 レシーバが、実体のものとポインタのもので定義方法が違う。 String() は、表示などで文字列化するときに使われる Stringer というインタフェースのメソッド。(toString() 相当) ```go func (task Task) String() string { // 引数なし,戻り値あり return fmt.Sprintf("%d) %s (%t)", task.Id, task.Detail, task.Done) } func (task *Task) Finish() { // 引数,戻り値無し task.Done = true } ``` ## 課題1 Task.Detail を引数で受け取った detail でまるっと上書きする Edit メソッドを実装しなさい。 ## IF 中括弧などいらない。 三項演算子はない。 ``` func (task Task) String() string { // 引数なし,戻り値あり var status string if task.Done { status = "done" } else { status = "not yet" } return fmt.Sprintf("%d) %s (%s)", task.Id, task.Detail, status) } ``` ## Slice 配列(固定長)とは別で、可変長な配列だと思えば良い。 追加の append は、結果を返すことに注意。 ```Go func main() { tasks := []*Task{ NewTask(1, "buy the milk"), NewTask(2, "eat the pie"), } tasks = append(tasks, NewTask(3, "go to the bank")) log.Printf("%s", tasks) } ``` 実際は、固定長配列のビューとなっている。 今回は make() を用いた初期化は省略。詳細は http://blog.golang.org/go-maps-in-action を参照のこと。 ## For 繰り返しを表現する方法は for のみ。 range はイテレータの役割を果たし、インデックスと要素を返す。 ```go for i, task := range tasks { log.Printf("%d %s", i, task) } // 宣言して使わない変数は許されないので // 使わないなら _ で宣言する for _, task := range tasks { log.Printf("%s", task) } ``` ## Tasks タスクをまとめる struct を定義してみる。 ``` type Tasks struct { Owner string Tasks []*Task file string } func NewTasks(owner string) *Tasks { file := owner + ".json" tasks := &Tasks{ Owner: owner, Tasks: make([]*Task, 0), file: file, } return tasks } ``` Tasks は *Task の空 slice で初期化している。 slice のメモリ確保は make() 関数を用いて行うことができ、 引数は length で今回は 0 にしている。 詳細はこちらを参照のこと。 [http://golang.org/ref/spec#Making_slices_maps_and_channels] ## 課題2 Tasks を以下のように定義し、 NewTasks 関数と Add メソッドを実装しなさい。 ```go type Tasks struct { Owner string Tasks []*Task // ここは空のスライスで初期化 } ``` 動作例 ```go func main() { tasks := NewTasks("Jxck") tasks.Add(NewTask(1, "buy the milk")) tasks.Add(NewTask(2, "eat the pie")) tasks.Add(NewTask(3, "go to the bank")) log.Println(tasks.Owner) for i, task := range tasks.Tasks { log.Printf("%d %s", i, task) } } ``` ## HTTP タスク内容を net/http で公開するサーバを作成。 まず index ページとしてリンクのみを表示するハンドラを作成。 ハンドラを登録したサーバを :3000 で起動。 ```go func IndexHandler(w http.ResponseWriter, r *http.Request) { // heredoc html := `<!DOCTYPE html> <title>tasks</title> <h1>here is your <a href="/tasks">tasks</a></h1> ` fmt.Fprintf(w, html) } func main() { http.HandleFunc("/", IndexHandler) http.ListenAndServe(":3000", nil) } ``` http.ResponseWriter は Writer というインタフェースを実装しており、書き込み可能なオブジェクト。 fmt.Fprintf は、第一引数に Writer を受け、第二引数をそこに書き込む。 ## 課題3 TasksHandler を作成し、とりあえず main でやっていたことを移して、 http://localhost:3000/tasks でタスクをリスト表示する。 実装は、 fmt.Fprintf を用いて ResponseWriter にガンガン書き込む感じで良い。 動作例(html) ```html <!DOCTYPE html> <title>tasks</title> <h1>Jxck's tasks</h1> <ul> <li>1) buy the milk (not yet)</li> <li>2) eat the pie (not yet)</li> <li>3) go to the bank (not yet)</li> </ul> ``` ## Template 標準で test/template と html/template があり、インタフェースは基本的に同じだが、 html/template の方はエスケープ処理などを標準で行ってくれるため今回はこちらを使う。 ```go func TasksHandler(w http.ResponseWriter, r *http.Request) { tasks := NewTasks("Jxck") tasks.Add(NewTask(1, "buy the milk")) tasks.Add(NewTask(2, "eat the pie")) // こういうのがあっても大丈夫 tasks.Add(NewTask(3, "<b>go to the bank</b>")) html := `<!DOCTYPE html> <title>tasks</title> <h1>{{.Owner}}'s tasks</h1> <ul> {{range .Tasks}} <li>{{.}}</li> {{end}} </ul> ` // 第二引数がエラーを返すイディオム TasksList, err := template.New("tasklist").Parse(html) if err != nil { log.Fatal(err) } TasksList.Execute(w, tasks) } ``` Go の関数は多値を返せる、 err の処理はイディオム。 実際はこれを処理したり、関数から返したりするが今回は log.Fatal はプロセスを落としている。 (今回は扱わないが、 panic/recover というエラーの制御方法もある http://blog.golang.org/defer-panic-and-recover) ## Closure tasks を受け取り http.Handler を返す関数にし、 main から tasks を渡せるようにする。 ```go func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { html := `<!DOCTYPE html> <title>tasks</title> <h1>{{.Owner}}'s tasks</h1> <ul> {{range .Tasks}} <li>{{.}}</li> {{end}} </ul> ` TasksList, err := template.New("tasklist").Parse(html) if err != nil { log.Fatal(err) } return func(w http.ResponseWriter, r *http.Request) { TasksList.Execute(w, tasks) } } func main() { // snip http.HandleFunc("/tasks", TasksHandler(tasks)) // snip } ``` ## JSON Tasks を encoding/json を用いてシリアライズする。 基本的には Marshal か MarshalIndent に渡すだけ。 戻り値は []byte というバイトスライスなので、文字列にする場合は変換が必要。 ```go // b, err := json.Marshal(tasks) // インデントなし b, err := json.MarshalIndent(tasks, "", " ") // プレフィックス、インデントあり if err != nil { log.Fatal(err) } log.Println(string(b)) // 文字列化 ``` ```json { "Owner": "Jxck", "Tasks": [ { "id": 1, "detail": "buy the milk", "done": false } ] } ``` 対応する key 名を変更したい場合はタグで指定する。 ```go type Task struct { Id int `json:"id"` Detail string `json:"detail"` Done bool `json:"done"` } ``` ```go type Tasks struct { Owner string `json:"owner"` Tasks []*Task `json:"tasks"` } ``` ## 課題4 http://localhost:3000/tasks.json で JSON で取得できる API を作成するため TasksJSONHandler を作成し、サーバに登録しなさい。 送信は fmt.Fprint で良いでしょう。 content-type とか細かいことは気にしない! ## 終わり 時間が余ったら、ファイル保存を行う。 ### Resources - [Go言語でWebAppの開発に必要なN個のこと](http://qiita.com/tenntenn/items/b8b27e32c28f7569f41a) - [Go言語の初心者が見ると幸せになれる場所](http://qiita.com/tenntenn/items/0e33a4959250d1a55045) ### WAF - [goweb](https://github.com/stretchr/goweb) - [martini](http://martini.codegangsta.io/) - [revel](http://robfig.github.io/revel/) ### 事例 [事例集](https://code.google.com/p/go-wiki/wiki/GoUsers) からピックアップ - [docker](https://www.docker.io/) - [packer](http://www.packer.io/) - [vitess](https://github.com/youtube/vitess) - [bitly](http://word.bitly.com/post/33232969144/nsq) - [github](http://techno-weenie.net/2013/11/2/key-value-logs-in-go/) - [cloudflare](http://blog.cloudflare.com/go-at-cloudflare) - [heroku](https://github.com/heroku/hk) - etc ## 回答 ### 課題3 ``` func TasksHandler(w http.ResponseWriter, r *http.Request) { tasks := NewTasks("Jxck") tasks.Add(NewTask(1, "buy the milk")) tasks.Add(NewTask(2, "eat the pie")) tasks.Add(NewTask(3, "go to the bank")) fmt.Fprintf(w, "<!DOCTYPE html><title>tasks</title>") fmt.Fprintf(w, "<h1>%s's tasks</h1>", tasks.Owner) fmt.Fprintf(w, "<ul>") for _, task := range tasks.Tasks { fmt.Fprintf(w, "<li>%s</li>", task) } fmt.Fprintf(w, "</ul>") } ``` ## 課題4 ```go func TasksJSONHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { b, err := json.MarshalIndent(tasks, "", " ") if err != nil { log.Fatal(err) } return func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, string(b)) } } ``` ## License The MIT License (MIT) Copyright (c) 2013 Jxck This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,27 @@ package main func (tasks *Tasks) WriteFile() error { b, err := json.MarshalIndent(tasks, "", " ") if err != nil { return err } err = ioutil.WriteFile(tasks.File, b, os.ModePerm) if err != nil { return err } return nil } func (tasks *Tasks) ReadFile() error { b, err := ioutil.ReadFile(tasks.File) if err != nil { return err } err = json.Unmarshal(b, tasks) if err != nil { return err } return nil } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,124 +4,109 @@ import ( "encoding/json" "fmt" "html/template" "log" "net/http" ) func init() { log.SetFlags(log.Lshortfile) } type Tasks struct { Owner string `json:"owner"` Tasks []*Task `json:"tasks"` } func NewTasks(owner string) *Tasks { tasks := &Tasks{ Owner: owner, Tasks: []*Task{}, } return tasks } func (tasks *Tasks) Add(task *Task) { tasks.Tasks = append(tasks.Tasks, task) } type Task struct { Id int `json:"id"` Detail string `json:"detail"` Done bool `json:"done"` } func NewTask(id int, detail string) *Task { task := &Task{ Id: id, Detail: detail, Done: false, } return task } func (task *Task) Finish() { // 引数,戻り値無し task.Done = true } func (task *Task) Edit(detail string) { // 引数あり,戻り値無し task.Detail = detail } func (task Task) String() string { // 引数なし,戻り値あり var status string if task.Done { status = "done" } else { status = "not yet" } return fmt.Sprintf("%d) %s (%s)", task.Id, task.Detail, status) } func IndexHandler(w http.ResponseWriter, r *http.Request) { html := `<!DOCTYPE html> <title>tasks</title> <h1>here is your <a href="/tasks">tasks</a></h1> ` fmt.Fprintf(w, html) } func TasksHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { html := `<!DOCTYPE html> <title>tasks</title> <h1>{{.Owner}}'s tasks</h1> <ul> {{range .Tasks}} <li>{{.}}</li> {{end}} </ul> ` TasksList, err := template.New("tasklist").Parse(html) if err != nil { log.Fatal(err) } return func(w http.ResponseWriter, r *http.Request) { TasksList.Execute(w, tasks) } } func TasksJSONHandler(tasks *Tasks) func(w http.ResponseWriter, r *http.Request) { b, err := json.MarshalIndent(tasks, "", " ") if err != nil { log.Fatal(err) } return func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, string(b)) } } func main() { tasks := NewTasks("Jxck") tasks.Add(NewTask(1, "buy the milk")) tasks.Add(NewTask(2, "eat the pie")) tasks.Add(NewTask(3, "go to the bank")) http.HandleFunc("/", IndexHandler) http.HandleFunc("/tasks", TasksHandler(tasks)) http.HandleFunc("/tasks.json", TasksJSONHandler(tasks)) http.ListenAndServe(":3000", nil) } -
Jxck revised this gist
Mar 14, 2014 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ # Go Kyoto (Go勉強会 そうだ京都、行こう) -
Jxck created this gist
Mar 14, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ # Go Kyoto (Go勉強会 そうだ京都、行こう) -
Jxck revised this gist
Mar 14, 2014 . 1 changed file with 33 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,8 +3,10 @@ package main import ( "encoding/json" "fmt" "html/template" "io/ioutil" "log" "net/http" "os" ) @@ -75,6 +77,33 @@ func (task Task) String() string { return fmt.Sprintf("%d) %s", task.Id, task.Detail) } func IndexHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "<html><a href=\"/tasks\">tasks</a></html>") } func TasksHandler(w http.ResponseWriter, r *http.Request) { tasks := NewTasks("Jxck") err := tasks.ReadFile() if err != nil { log.Fatal(err) } htmltemplate := `<html> <title>tasks</title> <h1>Owner {{.Owner}} <ul> {{range .Tasks}} <li>{{.}}</li> {{end}} </ul> </html>` t := template.New("t") template.Must(t.Parse(htmltemplate)) t.Execute(w, tasks) } func main() { tasks := NewTasks("Jxck") @@ -87,6 +116,10 @@ func main() { fmt.Println(task) } http.HandleFunc("/", IndexHandler) http.HandleFunc("/tasks", TasksHandler) http.ListenAndServe(":3000", nil) err = tasks.WriteFile() if err != nil { log.Fatal(err) -
Jxck revised this gist
Mar 13, 2014 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -37,8 +37,6 @@ func (tasks *Tasks) WriteFile() error { return err } err = ioutil.WriteFile(tasks.File, b, os.ModePerm) if err != nil { return err -
Jxck revised this gist
Mar 13, 2014 . 2 changed files with 3 additions and 2 deletions.There are no files selected for viewing
File renamed without changes.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -18,7 +18,8 @@ type Tasks struct { File string `json:"-"` } func NewTasks(owner string) *Tasks { file := owner + ".json" tasks := &Tasks{ Owner: owner, File: file, @@ -77,7 +78,7 @@ func (task Task) String() string { } func main() { tasks := NewTasks("Jxck") err := tasks.ReadFile() if err != nil { -
Jxck revised this gist
Mar 13, 2014 . 1 changed file with 21 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,38 +15,47 @@ func init() { type Tasks struct { Owner string `json:"owner"` Tasks []Task `json:"tasks"` File string `json:"-"` } func NewTasks(owner, file string) *Tasks { tasks := &Tasks{ Owner: owner, File: file, } return tasks } func (tasks *Tasks) Add(task Task) { tasks.Tasks = append(tasks.Tasks, task) } func (tasks *Tasks) WriteFile() error { b, err := json.MarshalIndent(tasks, "", " ") if err != nil { return err } log.Println(string(b)) err = ioutil.WriteFile(tasks.File, b, os.ModePerm) if err != nil { return err } return nil } func (tasks *Tasks) ReadFile() error { b, err := ioutil.ReadFile(tasks.File) if err != nil { return err } err = json.Unmarshal(b, tasks) if err != nil { return err } return nil } type Task struct { @@ -68,8 +77,9 @@ func (task Task) String() string { } func main() { tasks := NewTasks("Jxck", "tasks.json") err := tasks.ReadFile() if err != nil { log.Fatal(err) } @@ -78,7 +88,7 @@ func main() { fmt.Println(task) } err = tasks.WriteFile() if err != nil { log.Fatal(err) } -
Jxck revised this gist
Mar 13, 2014 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,8 +8,6 @@ import ( "os" ) func init() { log.SetFlags(log.Lshortfile) } @@ -70,6 +68,7 @@ func (task Task) String() string { } func main() { const FILENAME = "tasks.json" tasks, err := ReadTasks(FILENAME) if err != nil { log.Fatal(err) -
Jxck revised this gist
Mar 13, 2014 . 1 changed file with 30 additions and 15 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -23,6 +23,34 @@ func (tasks *Tasks) Add(task Task) { tasks.Tasks = append(tasks.Tasks, task) } func (tasks *Tasks) WriteFile(filename string) error { b, err := json.MarshalIndent(tasks, "", " ") if err != nil { return err } log.Println(string(b)) err = ioutil.WriteFile(filename, b, os.ModePerm) if err != nil { return err } return nil } func ReadTasks(filename string) (tasks Tasks, Error error) { b, err := ioutil.ReadFile(filename) if err != nil { return tasks, err } err = json.Unmarshal(b, &tasks) if err != nil { return tasks, err } return tasks, nil } type Task struct { Id int `json:"id"` Detail string `json:"detail"` @@ -42,13 +70,7 @@ func (task Task) String() string { } func main() { tasks, err := ReadTasks(FILENAME) if err != nil { log.Fatal(err) } @@ -57,14 +79,7 @@ func main() { fmt.Println(task) } err = tasks.WriteFile(FILENAME) if err != nil { log.Fatal(err) } -
Jxck revised this gist
Mar 11, 2014 . 2 changed files with 26 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,11 +2,14 @@ package main import ( "encoding/json" "fmt" "io/ioutil" "log" "os" ) const FILENAME = "tasks.json" func init() { log.SetFlags(log.Lshortfile) } @@ -26,7 +29,17 @@ type Task struct { Done bool `json:"done"` } func (task *Task) Finish() { task.Done = false } func (task *Task) Edit(detail string) { task.Detail = detail } func (task Task) String() string { return fmt.Sprintf("%d) %s", task.Id, task.Detail) } func main() { b, err := ioutil.ReadFile(FILENAME) @@ -40,8 +53,8 @@ func main() { log.Fatal(err) } for _, task := range tasks.Tasks { fmt.Println(task) } b, err = json.MarshalIndent(tasks, "", " ") This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,6 +10,16 @@ "id": 2, "detail": "eat the television", "done": false }, { "id": 3, "detail": "send mail to King", "done": false }, { "id": 4, "detail": "go to the moon", "done": false } ] } -
Jxck revised this gist
Mar 10, 2014 . 1 changed file with 0 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -26,10 +26,6 @@ type Task struct { Done bool `json:"done"` } const FILENAME = "tasks.json" func main() { -
Jxck revised this gist
Mar 10, 2014 . 2 changed files with 8 additions and 9 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -22,13 +22,13 @@ func (tasks *Tasks) Add(task Task) { type Task struct { Id int `json:"id"` Detail string `json:"detail"` Done bool `json:"done"` } // func (task *Task) Done() { // task.done = true // } const FILENAME = "tasks.json" @@ -45,7 +45,6 @@ func main() { } for i, task := range tasks.Tasks { log.Printf("%d %#v\n", i, task) } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ { "owner": "Jxck", "tasks": [ { "id": 1, "detail": "buy the zombie", @@ -12,4 +12,4 @@ "done": false } ] } -
Jxck revised this gist
Mar 10, 2014 . 1 changed file with 16 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,6 +4,7 @@ import ( "encoding/json" "io/ioutil" "log" "os" ) func init() { @@ -29,8 +30,10 @@ func (task *Task) Done() { task.done = true } const FILENAME = "tasks.json" func main() { b, err := ioutil.ReadFile(FILENAME) if err != nil { log.Fatal(err) } @@ -45,4 +48,16 @@ func main() { task.Done() log.Printf("%d %#v\n", i, task) } b, err = json.MarshalIndent(tasks, "", " ") if err != nil { log.Fatal(err) } log.Println(string(b)) err = ioutil.WriteFile(FILENAME, b, os.ModePerm) if err != nil { log.Fatal(err) } } -
Jxck revised this gist
Mar 10, 2014 . 1 changed file with 7 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,14 +15,18 @@ type Tasks struct { Tasks []Task `json:"tasks"` } func (tasks *Tasks) Add(task Task) { tasks.Tasks = append(tasks.Tasks, task) } type Task struct { Id int `json:"id"` Detail string `json"detail"` done bool } func (task *Task) Done() { task.done = true } func main() { @@ -39,6 +43,6 @@ func main() { for i, task := range tasks.Tasks { task.Done() log.Printf("%d %#v\n", i, task) } } -
Jxck created this gist
Mar 9, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,44 @@ package main import ( "encoding/json" "io/ioutil" "log" ) func init() { log.SetFlags(log.Lshortfile) } type Tasks struct { Owner string `json:"owner"` Tasks []Task `json:"tasks"` } type Task struct { Id int `json:"id"` Detail string `json"detail"` done bool } func (t *Task) Done() { t.done = true } func main() { b, err := ioutil.ReadFile("tasks.json") if err != nil { log.Fatal(err) } var tasks Tasks err = json.Unmarshal(b, &tasks) if err != nil { log.Fatal(err) } for i, task := range tasks.Tasks { task.Done() log.Println(i, task) } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ { "owner" : "Jxck", "tasks" : [ { "id": 1, "detail": "buy the zombie", "done": false }, { "id": 2, "detail": "eat the television", "done": false } ] }