Golang ことはじめ 目的~基礎構文まで
目的
目標
ブログアプリを作成し、Herokuへデプロイ
学習ステップ
- インストール方法
- hello wolrd
- 基礎構文
- DB接続
- フレームワーク(Gin)
- View
- Model
- Controller
- マイグレーション
- シーダー
- ルーティング
- ログイン / セッション
- パーミッション
- Heroku on Go lang
- ブログアプリ作成
Golangとは?
google謹製の新しい言語、と言っても2009年からプロジェクトはあったらしい。解決する課題として、
- シンプル
- 高速
- 並列性 + タイプセーフ
を重視している。
インストール
brewからサクッと入る。
brew install go
hello world
テキトーにディレクトリを作成し、そこからプログラムを書いてみる
mkdir ~/dev/go-sample cd ~/dev/go-sample touch hello.go
package main import "fmt" func main () { fmt.Printf("Hello, World") }
実行
go run hello.go > Hello, World
出力完了。
フォーマット
Goでは開発者間の無駄な争いを避けるため、最初からコーディング規約が整備されている。一つの例を言うと、ソフトタブ(半角スペース)ではなく、ハードタブ(タブ文字)でインデントを行うなど。
atomでは上記のgo fmtを含む便利なプラグインがあったので、インストールしておくと良い。
https://atom.io/packages/go-plus
追加でgithubからパッケ−ジを直接ダウンロードするように指示されるかもしれないが、下記のようにパスを通した上でインストールを行えば良い。
export GOROOT=/usr/local/opt/go/libexec export GOPATH=$HOME export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
例えば、fmtを利用したい場合、⌘+shift+p
からgo fmt
と入力することで対象ファイルがフォーマットされる。
基礎構文
参考:
mainパッケージとimport
package main import "fmt" //パッケージの追加 func main() { fmt.Println("HEELOO") }
変数
// 宣言 var message string = "hello world" // 一度に複数宣言をする var foo, bar, baz string = "foo", "bar", "baz" func main() { fmt.Println(message) //hello world fmt.Println(foo, bar, baz) //foo bar baz // 型推論と初期化シンタックス message2 := "hello2" fmt.Printf(message2) //hello2 // 定数 const message3 string = "HEEEELOOOOO" fmt.Printf(message3) var i int //ゼロ値で初期化 fmt.Println(i) }
条件式 /ループ式
func main() { a, b := 10, 100 // if後の()は必要なし、波かっこ省略パターンは存在しない // 三項演算子も存在しない、if elseを利用すること 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意外存在しない for i := 0; i < 10; i++ { fmt.Println(i) } // continue, break n := 0 for { n++ if n > 10 { break //ループを抜ける } if n%2 == 0 { continue //偶数の場合、一つ飛ばす } fmt.Println(n) //奇数のみ表示 } // switchでfizzbuzz s := 10 switch s { case 15: fmt.Println("FizzBazz") // fallthrough <-- 明示的に次の処理へ移りたい場合 case 5, 10: fmt.Println("Buzz") case 3, 6, 9: fmt.Println("Fizz") default: fmt.Println(s) } // 式のfizzbuzz switch { case s % 15 == 0: fmt.Println("FizzBazz") case s % 5 == 0: fmt.Println("Buzz") case s% 3 == 0: fmt.Println("Fizz") default: fmt.Println(s) } }
関数
func main() { // 関数実行 hello() //hello sum(2,3) //5 fmt.Println(sum_return(5,4)) //9 x, y := 3, 4 // この時点でx=4, y=3と逆になっている x, y = sum_return_multiple(x, y) fmt.Println(x,y) // コンパイルエラー、2つある戻り値を一つしか受け取らないため x = sum_return_multiple(x, y) // _を利用することで第二引数を無視することができる x, _ = sum_return_multiple(x, y) fmt.Println(x) //3 res, err := div(10,2) fmt.Println(res, err) //5, nill fmt.Println(literal()) } // 関数引数なし func hello() { fmt.Println("hello") } // 引数あり、複数の引数が同一型の場合は、最後の一つにまとめることができる func sum(i, j int) { fmt.Println(i+j) } // 戻り値 func sum_return (i, j int) int { return i+j } // 複数の値を返す // カンマ区切りをすることで、returnした型を指定し、値を返すことが可能 func sum_return_multiple (i, j int) (int, int) { return j, i } // 名前付き戻り値 func div(i, j int)(result int, err error) { if j == 0 { err = errors.New("divied by zero") return // return 0, err } result = i / j return // 5 } // 無名関数 func literal () { func (i, j int) { fmt.Println(i+j) }(2,4) }
配列 / スライス
func main() { arr_func1() arr_func2() // エラー // arr1 := [4]string{"a","b","c","d"} // fn(arr1) // 値渡しなのでarr2内は [a b c d]のまま arr2 := [4]string{"a", "b", "c", "d"} call_by_value(arr2) fmt.Println(arr2) slice() // 可変長引数 fmt.Println(sum(1, 3, 5, 7, 9)) } // 配列は固定長 func arr_func1() { var arr [4]string arr[0] = "a" arr[1] = "b" arr[2] = "c" arr[3] = "d" fmt.Println(arr[0]) //a } // 初期化、暗黙的配列長 func arr_func2() { arr1 := [4]string{"a", "b", "c", "d"} arr2 := [...]string{"a", "b", "c", "d"} fmt.Println(arr1, arr2) } // 配列の引数は配列長まで見るため、下記に[4]を渡すとエラー func fn(arr [5]string) { fmt.Println(arr) } // 配列は値渡し func call_by_value(arr [4]string) { arr[0] = "x" fmt.Println(arr) //[x b c d] } // 可変長配列の場合はスライスを利用する // 固定のarrayを使う機会はあまりない func slice() { // []内に値を入れなければslice // eg. var s[]string a := []string{"a", "b", "c", "d"} fmt.Println(a[0]) //a // appendでsliceの後に値を追加 a = append(a, "e", "f") fmt.Println(a) //[a b c d e f] // rangeを利用し、先頭から順に処理 for i, s := range a { // i = 添字 s = 値 fmt.Println(i, s) } // 値の部分切り出し //コロンで挟むとその範囲内の値 fmt.Println(a[2:4]) //c d //始点・終点を省略するとそれぞれ先頭 / 末尾となる fmt.Println(a[1:]) //b c d e f fmt.Println(a[:4]) //a b c d } // 可変長引数 func sum(nums ...int) (result int) { // numは[]int型 // keyは不要 for _, n := range nums { result += n } return }
map
func main() { map1() } func map1() { // key-value タイプ 初期化宣言 // intのkeyにstringのvalue // 最後の,も必須な模様 month := map[int]string{ 1: "January", 2: "Febrary", } fmt.Println(month) // valueの取り出し jan := month[1] fmt.Println(jan) //January // 2つ目の引数も受け取ると、指定したキーがマップにあるかどうかをboolで受け取る _, ok := month[1] if ok { fmt.Println("data exists!!") } // mapからデータを削除する場合はdelete関数 delete(month, 1) fmt.Println(month) // map[2:Febrary] // rangeでforを回すことも可能 // ただしmapの場合は、順序が保障されない for key, value := range month { fmt.Printf("%d, %s\n", key, value) } }
ポインタ
Goではポインタを利用することが可能。
func main () { var i int = 10 callByValue(i) //値渡し fmt.Println(i) //10 callByRef(&i) //参照渡し fmt.Println(i) //20 } // 値渡し func callByValue(i int) { i = 20 } // 参照渡し func callByRef(i *int) { *i = 20 }
次回は型についての学習をする。