Goことはじめ(JSONの取り扱い)
http://gihyo.jp/dev/feature/01/go_4beginners/0004 より学んだことメモ
package main import ( "fmt" "log" "encoding/json" ) // // 構造体にタグをつけることでJSON変換時の // ルールを定義することができる // 何も指定しない場合はpublicなフィールドだけ格納される // type Person struct { ID int `json:"id"` // id という名前で格納する Name string `json:"name"` Email string `json:"-"` // JSONに格納しない Age int `json:"age"` Address string `json:"address,omitempty"` // ,omitemptyで値が空なら無視 memo string } // JSONへの変換 func JsonStringifyFunc() { fmt.Println("構造体からJSONへの変換 ---------- ") person := &Person { ID: 1, Name: "Gopher", Email: "gopher@example.org", Age: 5, Address: "", memo: "golang lover", } // 構造体にデータを代入して // ポインタを渡すだけで、 // デフォルトフォーマットでJSON文字列の[]byteを生成できる b, err := json.Marshal(person) if err != nil { log.Fatal(err) } fmt.Println(string(b)) // 文字列に変換 // -> {"id":1,"name":"Gopher","age":5} } // JSONから構造体への変換 func JsonParseFunc() { fmt.Println("JSONから構造体への変換 ---------- ") var person Person b := []byte(`{"id":1,"name":"Hogeo","age":10}`) err := json.Unmarshal(b, &person) if err != nil { log.Fatal(err) } fmt.Println(person) } func main() { JsonStringifyFunc() JsonParseFunc() }
goenvインストールメモ
# インストール $ git clone https://github.com/syndbg/goenv.git ~/.goenv # ~/.bash_profile に追記 export GOENV_ROOT="$HOME/.goenv" export PATH="$GOENV_ROOT/bin:$PATH" eval "$(goenv init -)" # 反映 source ~/.bash_profile # 使えるバージョン確認 goenv install -l # 指定バージョンをインストール goenv install 1.12.3 # グローバルで使う goenv global 1.12.3 # rehashするとGOPATHが切り替わる goenv rehash echo ${GOPATH} /Users/kinosuke/go/1.12.3 # そのディレクリ以下で使う goenv local 1.12.3 # インストール済のGo一覧 goenv versions # depのインストール # ※GOPATH以下にインストールされる # npmみたいにパッケージをプロジェクトディレクトリ内にインストールできるようにするやつ go get -u github.com/golang/dep/cmd/dep # goenvの更新 cd $(goenv root) git pull
※GOPATHとは
Go言語での開発時の作業ディレクトリ。環境変数GOPATHに保存される。
明示的な指定がない場合はデフォルト設定が使われる。
> If no GOPATH is set, it is assumed to be $HOME/go on Unix systems and %USERPROFILE%\go on Windows.
Goことはじめ3
第3章 型システム―型を用いた安全なプログラミング:はじめてのGo―シンプルな言語仕様,型システム,並行処理|gihyo.jp … 技術評論社
より学んだことメモ。
package main import ( "fmt" ) // // 型の拡張 // 同じ型でも違う意味を持つもの(同じintでもIDを表すものと優先度を表すものとか)を混同しちゃうとバグになるようなときに使う。 // type ID int type Priority int func ProcessTask(id ID, priority Priority) { fmt.Println(id, priority); } func RunProcessTask() { fmt.Println("型の拡張 ---------- ") var id ID = 3 var priority Priority = 5 // typeが違うのでコンパイルエラーする // ProcessTask(priority, id) // typeが適合するのでこっちは通る ProcessTask(id, priority) } // // 構造体 // type Task struct { ID int Detail string // パッケージ外にpublicな属性は先頭大文字 done bool // パッケージ内でprivateな属性は先頭小文字 } func RunTask() { fmt.Println("構造体 ---------- ") // Task構造体の初期化 // 値を与えなかった場合はゼロ値で初期化される var task Task = Task{ ID: 1, Detail: "buy the milk", done: true, } // 定義順に値を渡すことでフィールド名を省略 // var task Task = Task{1, "buy the milk", true} fmt.Println(task.ID) fmt.Println(task.Detail) fmt.Println(task.done) } // // ポインタ型 // 引数の方を*Taskとすることでポインタを渡せる // これで参照渡しができる // func Finish(task *Task) { task.done = true } func RunFinish() { fmt.Println("ポインタ型 ---------- ") // &Taskでポインタを渡せる task := &Task{done: false} Finish(task) fmt.Println(task.done) // true } // // 構造体の初期化 // コンストラクタがないのでNew*というメソッドを作って初期化するのが通例 // func NewTask(id int, detail string) *Task { // new()メソッドは // 構造体のフィールドをすべてゼロ値で初期化して返す var task *Task = new(Task) task.ID = id task.Detail = detail return task } func RunNewTask() { fmt.Println("構造体の初期化 ---------- ") task := NewTask(1, "buy the milk") fmt.Printf("%+v\n", task) } // // 構造体にメソッドを追加する // func (task Task) String() string { // レシーバのコピーがわたされるので // ここで値を変えてもオリジナルの値は変わらない str := fmt.Sprintf("%d) %s", task.ID, task.Detail) return str } func (task *Task) Finish() { // ポインタ渡しなのでオリジナルの値が変わる task.done = true } func RunTaskFunc() { fmt.Println("構造体のメソッド追加 ---------- ") task := NewTask(1, "buy the milk") fmt.Printf("%s\n", task) task.Finish() fmt.Printf("%s\n", task.done) } // // インターフェース // // インターフェイスの定義 // 単純なインターフェースは*erという名前をつけるのが通例 type Stringer interface { String() string } // 引数にインターフェースを指定することで // 必要なメソッドを実装していると判断する func Print(stringer Stringer) { fmt.Println(stringer.String()) } // 何も定義しないインターフェースを使うと // どのような型も渡せるメソッドを作れる func Do(e interface{}) { // do something } type StringStruct struct { Text string } func (ss *StringStruct) String() string { return ss.Text; } func NewStringStruct(text string) *StringStruct { return &StringStruct{ Text: text, } } func RunInterface() { ss := NewStringStruct("インターフェース ---------- ") Print(ss) } // // 型の埋め込み // 継承の代わりになるもの // 下記ではUserをUserTaskに埋め込む例 // type User struct { FirstName string LastName string } func (u *User) FullName() string { fullname := fmt.Sprintf("%s %s", u.FirstName, u.LastName) return fullname } func NewUser(firstName, lastName string) *User { return &User{ FirstName: firstName, LastName: lastName, } } type UserTask struct { ID int Detail string done bool *User // Userを埋め込む } func NewUserTask(id int, detail, firstName, lastName string) *UserTask { task := &UserTask { ID: id, Detail: detail, done: false, User: NewUser(firstName, lastName), } return task } func RunEmbed() { fmt.Println("型の埋め込み ---------- ") task := NewUserTask(1, "buy the milk", "Jxck", "Daniel") // UserTaskにUserのフィールドが埋め込まれている fmt.Println(task.FirstName) fmt.Println(task.LastName) // UserTaskにUserのメソッドが埋め込まれている fmt.Println(task.FullName()) // UserTaskから埋め込まれたUser自体にもアクセス可能 fmt.Println(task.User) } // // 型の変換 // func CastFunc() { // キャスト var i uint8 = 3 var j uint32 = uint32(i) // uint8 -> uint32 fmt.Println(j) var s string = "abc" var b []byte = []byte(s) // string -> []bytes fmt.Println(b) // キャストに失敗した場合はパニックが発生する // a := int("a") } func TypeAssertionFunc(value interface{}) { // TypeAssertion // 第1戻り値はその型に変換された値が返り、 // 第2戻り値は成否を返す // (第2戻り値を指定しなかった場合はパニック起こる) s, ok := value.(string) if ok { fmt.Printf("value is string: %s\n", s) } else { fmt.Printf("value is not string\n") } } func TypeSwitchFunc(value interface{}) { switch v := value.(type) { case string: fmt.Printf("value is string: %s\n", v) case int: fmt.Printf("value is int: %d\n", v) case Stringer: fmt.Printf("value is Stringer: %s\n", v) } } func RunType() { fmt.Println("型の変換 ---------- ") CastFunc() TypeAssertionFunc("StringValue") TypeAssertionFunc(1) TypeSwitchFunc("StringValue!!") TypeSwitchFunc(10) } func main() { RunProcessTask() RunTask() RunFinish() RunNewTask() RunTaskFunc() RunInterface() RunEmbed() RunType() }
チャネルにバッファを設けて処理ブロックを制御
package main import ( "fmt" "time" ) func main() { // バッファを3として設定 ch := make(chan string, 3) go func() { time.Sleep(time.Second) s := <-ch // 1秒後にデータを読み出す fmt.Printf("get %s\n", s) }() ch <- "a" // ブロックしない fmt.Println("put a") ch <- "b" // ブロックしない fmt.Println("put b") ch <- "c" // ブロックしない fmt.Println("put c") ch <- "d" // 1秒後にデータが読み出されるまでブロック fmt.Println("put d") }
geminaboxにgem登録する手順メモ
# 準備 gem install geminabox --no-ri --no-doc # Gemを作る gem build -V ***.gemspec mv ***-0.1.0.gem pkg/. # アップロードする gem inabox ./pkg/***-0.1.0.gem --host http://example.com
Goことはじめ2
第2章 基本文法―覚えやすいコンパクトな言語仕様:はじめてのGo―シンプルな言語仕様,型システム,並行処理|gihyo.jp … 技術評論社
より学んだことメモ。
基本的な文法について
package main import ( "fmt" "os" "errors" "log" // f "fmt" -> と記述すると f.Println()のようにアクセスできる // . "strings" -> と記述すると ToUpper('xx') とパッケージ指定なしでアクセスできる ) // // 代入処理について // func substitute() { fmt.Println("substitute -------------------- ") // 変数代入 var message string = "hello world" fmt.Println(message) // 関数の中では型推論して代入もできる message2 := "hello world" fmt.Println(message2) // 定数定義 const Hello string = "Hello Const" // 変数を宣言して明示的に初期化しなかった場合は // ゼロ値で初期化される // 整数型: 0 // 浮動小数点型: 0.0 // bool: false // string: "" // 配列: 各要素がゼロ値の配列 // 構造体: 各フィールドがゼロ値の構造体 // そのほかの型: nil const message3 string = ` 複数行に渡る 文字列を使うときは バッククォートでくるる ` } // // 条件分岐・繰り返し // func repeat() { fmt.Println("repeat -------------------- ") // if文 Goでは丸かっこは不要 a, b := 10, 100 if a > b { fmt.Println("a is larger than b") } else if a < b { fmt.Println("a is smaller than b") } else { fmt.Println("a equals b") } // 繰り返しはfor文だけ n := 0 for n < 10 { fmt.Printf("n = %d\n", n) n++ } // 無限ループ・break・continue m := 0 for { m++ if m > 10 { break // ループを抜ける } if m%2 == 0 { continue // 偶数なら次の繰り返しに映る } fmt.Println(m) // 奇数のみ表示 } // switch文 // breakは書かなくていい p := 10 switch p { case 15: fmt.Println("FizzBuzz") case 10: fmt.Println("Buzz") case 3, 6, 9: // カンマ切りで複数指定可能 fmt.Println("Fizz") // そのまま下に処理をおろしたい場合は // fallthrough // と記述する(逆break) default: fmt.Println(p) } // if文と同じようにかける q := 10 switch { case (p % 15 == 0): fmt.Println("FizzBuzz") case (p % 5 == 0): fmt.Println("Buzz") default: fmt.Println(q) } } // // 関数 // // 引数の後に型を指定する func sum1(i, j int) { // func sum(i int, j int) と同じ fmt.Println(i + j) } // 戻り値がある場合は引数の次に指定する func sum2(i, j int) int { return i + j } // 関数は複数の値を返せる func swap(i, j int) (int, int) { return j, i } // 内部で発生したエラーは戻り値で表現する func errorFunc() { // _ で 第1戻り値を無視 _, err := os.Open("sample.txt") if err != nil { // エラー処理 fmt.Println("file open error") } fmt.Println("file open success") } // 自作のエラーはerrorsパッケージを用いて作ることができる func div(i, j int) (int, error) { if j == 0 { // 自作のエラーを返す return 0, errors.New("divied by zero") } return i / j, nil } // 名前付き戻り値 // 関数内ではゼロ値で初期化された変数として扱われる func divWithName(i, j int) (result int, err error) { if j == 0 { err = errors.New("divied by zero") return // return 0, err と同じ } result = i / j return // return result, nil と同じ } // 関数はオブジェクト func wrapFunc() { // 関数リテラル(無名関数) // 即時実行される func(i, j int) { fmt.Println(i + j) }(2, 4) // 関数は変数に代入できる var sum func(i, j int) = func(i, j int) { fmt.Println(i + j) } sum(2, 3) } // // 配列 // func arrayFunc() { fmt.Println("arrayFunc -------------------- ") // Goの配列は固定長 var arr [4]string arr[0] = "a" arr[1] = "b" arr[2] = "c" arr[3] = "d" fmt.Println(arr[0]) // 宣言と代入 arr2 := [4]string{"a", "b", "c", "d"} fmt.Println(arr2) // 暗黙的なサイズ指定 arr3 := [...]string{"a", "b", "c", "d"} fmt.Println(arr3) // 長さの違う配列は別の型 // 関数に配列を渡す場合は"値渡し"になる } // // スライス // スライスは,可変長配列として扱うことができます。 // 配列を直接使うのは,シビアなメモリ管理が必要な一部のプログラムだけなので, // 基本的にはスライスを用います。 // func sliceFunc() { fmt.Println("sliceFunc -------------------- ") // スライスの型には長さの情報はない var s []string // 追加 s = append(s, "a") // 追加した要素を返す s = append(s, "b") s = append(s, "c", "d") fmt.Println(s) // [a b c d] // 結合 s1 := []string{"a", "b"} s2 := []string{"c", "d"} s1 = append(s1, s2...) // s1にs2を追加 fmt.Println(s1) // [a b c d] // 繰り返し処理 // rangeは配列,スライス,string,マップに対して使うことができる s11 := []string{"a", "b", "c", "d"} for i, v := range s11 { // i = 添字, v = 値 fmt.Println(i, v) } // 値の切り出し s21 := []int{1, 2, 3, 4, 5} fmt.Println(s21[2:4]) // [2 3] fmt.Println(s21[0:len(s)]) // [0 1 2 3 4 5] fmt.Println(s21[:3]) // [0 1 2] fmt.Println(s21[3:]) // [3 4 5] fmt.Println(s21[:]) // [0 1 2 3 4 5] // 可変長引数 var _sum func(nums ...int) (result int) = func(nums ...int) (result int) { // numsは []int型 for _, n := range nums { result += n } return } fmt.Println(_sum(1, 2, 3, 4)) // 10 } // // マップ // マップは値をKey-Valueの対応で保存するデータ構造 // func mapFunc() { fmt.Println("mapFunc -------------------- ") // 宣言 key=int, value=string var month map[int]string = map[int]string{} month[1] = "January" month[2] = "February" fmt.Println(month) // 宣言と初期化を一緒にする場合 month2 := map[int]string { 1: "January", 2: "February", } fmt.Println(month2) // 値を取り出す jan := month[1] fmt.Println(jan) // マップにキーが存在するかチェック _, ok := month[1] if ok { fmt.Println("month[1] is present") } // 要素の削除 delete(month, 1) // 繰り返し処理 // 処理順番は保証されない for key, value := range month { fmt.Printf("%d %s\n", key, value) } } // // ポインタ // ポインタを使うことで参照渡しができる // func callByValue(i int) { i = 20; // 値を上書きする } func callByRef(i *int) { *i = 20; // 参照先を上書きする } // // 関数を抜けるときに必ず実行 // func deferFunc() { fmt.Println("deferFunc -------------------- ") file, err := os.Open("./error.go") if err != nil { fmt.Println("FileOpenError") } // 関数を抜ける前に必ず実行される defer file.Close() // 正常処理 fmt.Println("deferFuncProcess") } // // パニックと後処理 // func panicFunc() { fmt.Println("PanicFunc -------------------- ") // 後処理 defer func() { // パニックで発生したエラーはrecoverで取得できる err := recover() if err != nil { log.Print(err) } }() a := []int{1, 2, 3} fmt.Println(a[10]) // パニック発生 // 自前でパニックを起こすこともできる // panic(errors.New("index out of range")) } func main() { substitute() repeat() fmt.Println("Function -------------------- ") sum1(1, 2) s := sum2(2, 3) fmt.Println(s) x, y := swap(3, 4) fmt.Println(x, y) errorFunc() _, err := div(10, 0) if err != nil { log.Print(err) // Fatalを使用するとステータス=1で終了する // log.Fatal(err) } m, err := divWithName(10, 2) fmt.Println(m) wrapFunc() arrayFunc() sliceFunc() mapFunc() fmt.Println("Pointer -------------------- ") var i int = 10; callByValue(i) // 値渡し fmt.Println(i) // 10 callByRef(&i) // 参照渡し fmt.Println(i) // 20 deferFunc() panicFunc() }
シェルのtestコマンド
シェルのtestコマンドの理解が怪しかったので、使い方をメモしておく。
#!bin/sh # $?==0 で正常終了 # 数値の比較 ## 1 == 1 test 1 -eq 1; echo $? ## 1 != 2 test 1 -ne 2; echo $? ## 1 < 2 test 1 -lt 2; echo $? ## 2 > 1 test 2 -gt 1; echo $? ## 1 <= 1 test 1 -le 1; echo $? ## 1 >= 1 test 1 -ge 1; echo $? # 文字列の比較 ## "abc" == "abc" test "abc" = "abc"; echo $? ## "abc" != "aaa" test "abc" != "aaa"; echo $? # 空チェック ## 変数に値が入っているか test -n HOGE; echo $? ## 変数が空か test -z HOGE; echo $? # ファイルチェック ## file2が新しいか touch file1 touch file2 test ./file1 -ot ./file2 ## fileが存在するか touch file3 test -f ./file3; echo $? ## fileが存在しない test ! -f ./file4; echo $? ## ディレクトリが存在するか mkdir dir1 test -d ./dir1; echo $? # 略式 [ ] # [ は testコマンド # ] は [を使うためのオプション [ 1 -lt 2 ]; echo $? # AND条件 OR条件 [ 1 -eq 1 ] && [ 1 -lt 2 ] || [ 2 -eq 2 ]; echo $? # if文 ## 一般的な書き方 if [ 1 -eq 1 ] && [ 1 -lt 2 ] || [ 2 -eq 2 ]; then echo "if文の中の実行" fi ## これでもOK if [ 1 -eq 1 ] && [ 1 -lt 2 ] || [ 2 -eq 2 ] then echo "if文の中の実行" fi
Goことはじめ
http://gihyo.jp/dev/feature/01/go_4beginners で学んだことをメモしていく。
はじめに
# インストール brew install go # ./bash_profileの設定 export GOROOT=/usr/local/opt/go/libexec export GOPATH=$HOME export PATH=$PATH:$GOROOT/bin:$GOPATH/bin # ソースコードから実行 go run hello.go # コンパイルして実行 go build hello.go ./hello # コーディング規約に合わせてフォーマット go fmt hello.go # パッケージ(ここではfmt)のドキュメントを表示 go doc fmt
プロジェクトを作る
# プロジェクトディレクトリ基本形 # Goのコマンドは,このGOPATHとその下にある先の3つのディレクトリの命名規則を用いて,Makefileなどの構成ファイルは一切なしで,依存関係を解決してビルドできるようになっている。 tree hello/ ├── bin ├── pkg └── src # プロジェクトディレクトリにパスを通す cd hello export GOPATH=`pwd` # helloをGOPATHに登録 # ソースを書く1 cat src/hello/hello.go # --- package hello var Message string = "hello world" # ソースを書く2 cat src/main/main.go # --- package main import ( "fmt" "hello" ) func main() { fmt.Println(hello.Message) // hello world } # 実行してみる cd $GOPATH/src/main go run main.go hello world # 実行ファイルをbin以下に作る cd $GOPATH/src/main go install # binにパスを通しておくと、すぐに実行できて便利 export PATH=$PATH:$GOPATH/bin main hello world