Posted at

Golangの基本文法をおさえてみる

More than 3 years have passed since last update.

http://go-tour-jp.appspot.com/#1

Golangが熱いと小耳に挟んだので読める程度に基本的な文法を抑えていきます。


Hallo World

package main

import("fmt")
func main() {
fmt.Println("Hallo World")
}

開始点:package mainが必要


int:初期値 0

float32: 初期値 0

bool: 初期値 false

string: 初期値 ""

complex64: 初期値 (0+0i)

bool

string

int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

rune // int32 の別名
// Unicode のコードポイントを表す

float32 float64

complex64 complex128


配列

p := []int{2, 3, 5, 7, 11, 13}

配列のfor文

for i := 0; i < len(p); i++ {

fmt.Printf("p[%d] == %d\n", i, p[i])
}

部分配列

p[<start>:<end>]

p[1:4]
p[1:]//p[1:<last>]
p[:4]//p[0:4]

配列のメモリ確保

make([]int, 5) // len(a)=5

make([]int, 0, 5) // len(b)=0, cap(b)=5


Map

var m map[string]Vertex

m = make(map[string]Vertex)

Mapリテラル

最終行もカンマ必須

var m = map[string]int{

"Bell Labs": 1,
"Google": 2 ,
}

アクセッサ

m[key] = elem

elem = m[key]
delete(m, key)

キーの有無チェック

elem, ok = m[key]//存在すればok=true


変数の宣言

var x, y int

初期値が与えられた場合、型宣言不要

var x, y, z = 0, 0.1, "str"

関数内でのみ宣言不要(暗黙的な宣言)

func f(){

x := a
}


定数の宣言

const <name> = <val>

const (

<name1> = <val1>
<name2> = <val2>
)


ループ

for文のみ whileなし

for i := 0; i < 10; i++ {

}

whileと同等

for i < 10 {

}

無限ループ

for {

}

要素の繰り返し

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

for i, v := range pow {

}

indexの破棄

for _, v := range pow {

}


条件分岐

if x < 0 {

}

if文内でのみ有効な変数の宣言

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

return v
}

else文

if v < lim {

} else {

}


switch文

自動でbreakする

caseに式が使える

    switch time.Saturday {

case today + 0:
fmt.Println("Today.")
case today + 1:
fmt.Println("Tomorrow.")
case today + 2:
fmt.Println("In two days.")
default:
fmt.Println("Too far away.")
}

条件のないswitch=if-elseと同等

    switch {

case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}


関数

func <method>(<arg> <type>, ...) <type>{}

func add(x int, y int) int {

return x + y
}

引数が同じ型の場合、最初を省略できる。

func add(x, y int) int {

return x + y
}

戻り値を複数返すことが可能

func double_string() (string, string){

return "a", "b"
}

戻り値のパラメータ化が可能。

戻り値に名前を付けるとreturn文で明示しなくてよい。

func f()(s string){

s = "aaa"
return
}

変数に代入できる

 hypot := func(x, y float64) float64 {

}

Goの関数はクロージャー

func adder() func(int) int {

sum := 0
return func(x int) int {
sum += x
return sum
}
}


構造体

type Vertex struct {

X int
Y int
}

初期化

Vertex{1, 2}

アクセス

v = Vertex{1, 2}

v.X

ポインタ

 p := Vertex{1, 2}

q := &p
q.X

フィールドの一部のみ初期化(Name構文)

Vertex{X: 1}

newを使用した初期化。ポインタが渡される

フィールドは暗黙的な初期化が行われる。

var v *Vertex = new(Vertex)

v := new(Vertex)


メソッド

GoにはClassがないが構造体にメソッドをつけられる

func (v *Vertex) Abs() float64 {

return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}

構造体以外の任意の型も可能

type MyFloat float64

func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
f := MyFloat(-math.Sqrt2)
f.Abs()


インターフェース

type Abser interface {

Abs() float64
}

実装側でインターフェース名を明示する必要なし

type MyFloat float64

func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
var a Abser
a = MyFloat(-math.Sqrt2)


エラーハンドリング

type error interface {

Error() string
}

type MyError struct {

When time.Time
What string
}

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

func Sqrt(f float64) (float64, error) {}


キャスト

z := float64(1)


モジュールのインポート

import(

 "module1"
"moduel2"
)


モジュールのエクスポート

名前を大文字で始める。


  • pi:エクスポートされない

  • Pi:エクスポートされる


Web servers

package http

type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}

package main

import (
"fmt"
"net/http"
)

type Hello struct{}

func (h Hello) ServeHTTP(
w http.ResponseWriter,
r *http.Request) {
fmt.Fprint(w, "Hello!")
}

func main() {
var h Hello
http.ListenAndServe("localhost:4000", h)
}


Goroutines

別スレッド実行

go f(x, y, z)

同期処理(Channels)

ch <- v    // v をチャネル ch へ送る。

v := <-ch // ch から受信し、
// 変数を v へ割り当てる

以上です。マルチスレッディングが文法レベルでサポートされてるのはいいですね。