Go学習メモ
Go言語を学習する時に見たものや学んだことを書き残していく
学習時の参考資料
packages
Javaなどと同様にpackageがある
他のpackageをインポートして使うことができる
package main
がエントリポイントになる
Imports
package main
// 一つずつimportを書けるが
import "fmt"
import "math"
package main
// 以下のようにimportをまとめられる
import (
"fmt"
"math"
)
Export
Goでメソッドなどを公開する場合はメソッド名を大文字で始める
パッケージ外から大文字で始まるもの以外は参照・アクセスできない
fmt.Println("Exported!")
Functions
関数は引数を0以上持てる
宣言はfuncで始める
func add(x int, y int) int {
return x + y
}
// 以下のように引数の型が同じならまとめることもできる
func add(x, y int) int {
return x + y
}
複数の返り値を返せる
func swap(a, b string) (string, string) {
return b, a
}
返り値には名前をつけることもできる
この場合returnに返り値を渡さずとも対応した変数が返される
ただ、長い関数だと可読性が悪くなるので使い所は注意
func split(sum int) (x, y int) {
x = sum * 4 / 7
y = sum - x
return
}
Variables
変数はvarで宣言する
変数は関数の中でもトップレベルでも宣言できる
型は変数の後につける
var x int
// 初期化
var y int = 3
// shorthand
// := でvarと型宣言を省略する、型は右辺から型推論される
z := 12
Constants
定数はconst
で宣言する
:=
は使えない
const Pi = 3.14
Basic types
プリミティブ型は以下
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8のalias
rune // int32のalias
float32 float64
complex64 complex128
初期値は数値系は0
、boolはfalse
、stringは""
型変換
キャストする場合はType(variable)
のようにする
var x int = 36
var y float64 = float64(x)
for
JavaやJavascriptに近い
ただ、ループの条件は()
でくくらない
for i := 0; i< 100; i++ {
fmt.Println(i)
}
// 最初と最後の式を省略してwhileのようにも扱える
// 比較式も省略すると無限ループになる
sum := 1
for sum < 10000 {
sum += sum
}
if
forと同様に条件を()
でくくらない
他条件をつける場合はelse if
、またelse
を使える
if x < 0 {
return
}
// 条件の前に式を入れることができる
if v := math.Pow(x, n); v < lim {
return v
}
switch
breakを明示的に書かなくても条件を満たすcaseで実行は止まる
x := 0
if x < 100 {
switch x += 1; x {
case x % 15 == 0:
fmt.Println("fizzbuzz")
case x % 3 == 0:
fmt.Println("fizz")
case x % 5 == 0:
fmt.Println("buzz")
default:
fmt.Println(x)
}
}
defer
実行した関数がreturnするまで、遅延して実行できる
複数deferがある場合はstackのようにLIFOになっている
func main() {
defer fmt.Println("world")
fmt.Println("Hello")
}
Pointer
ポインタ型は型に*
をつける
初期値はnil
ポインタ演算は無い
var p *int
// 変数からポインタを取り出したい場合は`&`を変数につける
x := 12
p = &x
// ポインタに格納された値を取得する場合
fmt.Println(*p)
// ポインタを使って値を格納する場合
*p = 36
Struct
構造体
type Vector struct {
X, Y int
}
func main() {
v := Vector{2, 4}
v2: = Vector{X: 1, Y: 2}
v3 := Vector{} // X = 0, Y = 0
fmt.Println(v)
v.X = 10
fmt.Println(v)
// ポインタアクセスする場合は*を省略できる
p := &v
p.Y = 20
fmt.Println(v)
}
Array
変数宣言時に配列のサイズが決まり、変更することはできない
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a)
Slice
サイズを動的に変更できる配列
Sliceは元の配列への参照を持つため、値を変更すると元の配列の値も変更される
Sliceの初期値はnil
list := [6]int{1, 2, 3, 4, 5, 6}
var s []int = list[1:4]
fmt.Println(s)
// lenとcapでそれぞれSliceの長さと容量を取得できる
fmt.Printf("len=%d cap=%d", len(s), cap(s))
// makeという組み込み関数で0埋めしたSliceを生成することもできる
a := make([]int, 10)
fmt.Println(a)
// appendで値を追加できる
a = append(a, 1)
fmt.Println(a)
Map
連想配列
初期値はnil
m = make(map[string]int) // [keyの型]valueの型
m["Japan"] = 47
fmt.Println(m)
Range
SliceやMapをforで扱うのに使えるrangeというものがある
各要素のindexとvalueをiterableに取り出す
var s = []int{1, 2, 4}
for i, v := range s {
fmt.Printf("i: %d, v: %d", i, v)
}
Method
GoはClassは無いが型に対してメソッドを定義できる
メソッドを定義できるのは同じパッケージで定義されている型のみ
type Person struct {
firstName, lastName string
age int
}
func (p Person) fullName() string {
return firstName + lastName
}
// ポインタをレシーバにもできる
func (p *Person) growOld() {
p.age += 1
}
func main() {
p := Person{"太郎", "山田", 20}
fmt.Println(p.fullName())
}
Interface
Javaなどのinterfaceと同様に実装するメソッドを定義する
この型を宣言した変数にinterfaceで定義したメソッドが無いとエラーになる
type Abser interface {
Abs() float64
}
// 空のinterface型はTypeScriptで言うところのany型になる
var i interface{}
Type assertion
型をassertしたい場合は以下のようにする
t, ok := i.(T)
Errors
組み込みでエラーを表す値でerror
がある
型は以下のようになっている
type error interface {
Error() string
}
Goroutines
- Goでの並行処理を実現するための仕組み
- 軽量スレッド
- 関数呼び出しの前にgoキーワードをつけると生成される
- 同じアドレス空間を共有するので、共有メモリの扱いには気をつける
func main() {
go func() {
fmt.Println("別goroutine")
}()
time.Sleep(100)
fmt.Println("main goroutine")
}
Channels
- goroutine間でデータをやり取りするための仕組み
- 共通の変数を参照するようにすると競合してしまう
- 送受信できるデータの型は宣言時に指定する
- Channelはバッファを持たせることができる
- 指定しないと容量0
- 送信時にチャネルのバッファがいっぱいだとブロックする
- 受信時にチャネルが空だとブロックする
- 送信側からcloseすることもできる
// 初期化
ch1 := make(chan int, 10)
// チャンネルに送信
ch1 <- 10
// チャンネルから受信
v1 := <- ch1
// fotとselectで複数のgoroutingとの通信を扱う
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}