LoginSignup
0
0

More than 5 years have passed since last update.

Go メモ

Last updated at Posted at 2018-04-24

記法

MixedCaps or mixedCaps
戦闘が大文字の場合,パッケージ外にエクスポートされることを意味する

変数宣言

変数名 型 で宣言

j int = 1

varで複数の変数を宣言できる

var i, j int = 1, 2

暗黙の変数宣言

関数内でのみ :=で暗黙的な変数の宣言が可能

func main() {
    k := 3
}

型変換の明示

Goではint型とfloat型などでも明示的に変換しないとエラーをはく
暗黙の変数宣言の際は代入される値から推論

ループ

whileみたいに書きたいときはforの宣言とイテレータを書かないことで実現する

for sum < 1000 {
    sum += sum
}

ループ条件を抜くことで無限ループを簡潔に記述することもできる

if

ifの条件式中に変数を書くことができる
変数はifやelse文の中でのみ有効

if v := math.Pow(x, n); v < lim {
    return v
}

switch

該当するcaseのみを実行
caseは定数である必要がない
breakは自動的に入るので書く必要なし

defer

deferに渡した関数は呼び出し元の関数がreturnされたあとに実行される
複数ある場合はあとに渡したものから実行される

func main() {
   defer fmt.Println("こちらがあと")
   fmt.Println("こちらが先")
}

ポインタ

var p *int
i := 42
p = &i
fmt.Println(*p) // 42

配列

配列のサイズは変えることはできない
a[low:high]でスライスできる(high-1までとれる)
※スライスはあくまでもとの配列への参照

以下のスライスは等価

a[0:10]
a[:10]
a[0:]
a[:]

len()で長さ,cap()で容量を取得できる
ここでいう容量とはスライスの最初の要素から数えてもととなる配列の要素数である

make関数を利用するうことで動的サイズの配列を作成できる
make([]type, length, capacity)
makeでつくった配列をスライスした場合,中身はゼロ値で埋められる

map

Rubyのハッシュ, Pythonの辞書てきなやつ

map[Type]Type // "":""のmap 

closure(クロージャ)

クロージャは、それ自身の外部から変数を参照する関数値
関数を返す関数で初期化すると関数を返す関数内の変数の値を保持できる
使い所が難しいそう…

Methods

Goにはクラスの仕組みはないがmethodを定義できる

// 型に生やす場合
func (変数 生やしたい型) methodName(引数 ) 返却する型 {}
// 通常の関数
func methodName(引数 ) 返却する型 {}

※レシーバ(メソッドの呼び出される側→fmt.Printlnのfmt)を伴うメソッドの宣言はレシーバ型が同じパッケージに存在する必要がある

Methodには引数のコピーを渡すため,引数となる値そのものを変えたい場合はポインタレシーバにする必要がある
https://go-tour-jp.appspot.com/methods/4

以下のような時,vは変数だがポインタレシーバを保つ場合,v.Scale(2)(&v).Scale(2)として解釈する

func (v *Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

func main() {
    v := Vertex{3, 4}
    v.Scale(2)
    fmt.Println(v) // &{6, 8}
}

逆にポインタを変数として解釈も可能
この場合、 p.Abs() は (*p).Abs() として解釈される

func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    p := &Vertex{4, 3}
    fmt.Println(p.Abs())
}

ポインタレシーバを使う理由
1. レシーバが指す先の変数を変えたい
2. メソッド呼び出しのたびの変数のコピーを避けるため
一般的には変数レシーバかポインタレシーバのどちらかで統一すべき

interface

メソッドのシグニチャの集まりで定義
メソッドを定義した変数をinterface型に持たせることができる
https://go-tour-jp.appspot.com/methods/9

interfaceの説明
https://qiita.com/tenntenn/items/eac962a49c56b2b15ee8

空のインターフェースは任意の型の値を保持できる.
var i interface{}

インターフェースの値愛が具体的な型を保持し, その方の値をtni
代入することを意味する
成功したかのbool値も取れる
もしfalseの場合, Typeのゼロ値が代入される

t := i.(Type)
t, ok := i.(Type) // ok = true, false

以下はStringerインターフェースを使ってfmt.Stringerインターフェースを実装している
つまりstringとして扱うことができる

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
    a := Person{"Arthur Dent", 42}
    z := Person{"Zaphod Beeblebrox", 9001}
    fmt.Println(a, z)
}

エラー状態をerrorインターフェースで実装する
一般的にはerror変数がnilなら成功, それ以外ならErrorを出力と言った形をとる
Errorの中身を以下のように作っておくことも多い

i, err := strconv.Atoi("42")
if err != nil {
    fmt.Printf("couldn't convert number: %v\n", err)
    return
}
fmt.Println("Converted integer:", i)

type MyError struct {
    When time.Time
    What string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("at %v, %s",
        e.When, e.What)
}

並列処理 goroutine

並列処理周り
selectがよくわからなかった

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // receive from c

    fmt.Println(x, y, x+y)
}

Exercise

Map


func WordCount(s string) map[string]int {
    wordCounter := make (map[string]int)
    words := strings.Fields(s)
    fmt.Println(words)  
    for i := 0; i < len(words); i++ {
        _, ok := wordCounter[words[i]]
        if ok {
            wordCounter[words[i]] += 1
        } else {
            wordCounter[words[i]] = 1
        }
    }
    return wordCounter
}

func main() {
    wc.Test(WordCount)
}

Stringers

package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
func (ip IPAddr) String() string {
    return fmt.Sprintf("%v.%v.%v.%v", ip[0], ip[1], ip[2], ip[3] )
}

func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %v\n", name, ip)
    }
}

Errors

package main

import (
    "fmt"
)

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
    return fmt.Sprintf("cannot Sqrt negative number: %g", float64(e))
}

func Sqrt(x float64) (float64, error) {
    x64 := float64(x)
    xn := float64(0)
    n  := 10

    if x < 0 {
        return 0, ErrNegativeSqrt(x)
    }

    for ; xn * xn < 64; xn++ {
    }

    for i := 0; i < n; i++ {
        xn = (xn + x64 / xn) / 2
    }

    return xn, nil
}

func main() {
    fmt.Println(Sqrt(2))
    fmt.Println(Sqrt(-2))
}

Gpを正しく書くために

gofmt ファイルフォーマッター
goimport gofmtの上位互換. import周りを挿入削除してくれる
go vet バグになりそうなコードの検出
golint Goらしくないコードを検出

プロジェクト

プロジェクト名は 小文字
testdata/や_で始まるディレクトリはGoのパッケージとしてみなさない

ライブラリ

Web Application FrameWork

  • Gin
  • Echo
  • Iris
  • Goa

O/R マッパー

  • Xorm
  • GORM

  • gorp
  • beego orm

環境変数, 設定, key管理

  • toml

APIの作り方

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0