- 真偽値 bool
- 文字列 string
- 整数 int(8, 16, 32, 64)
- 符号なし整数 uint(8, 16, 32 64)
- バイト byte (uint8 の別名)
- 文字 rune (Unicodeのコードポイントを指す。int32 の別名)
- 浮動小数点 float32(64)
- 複素数 complex64(128)
int や uintが示すビット数は、システムに依存する。 32bitの場合は32、64bitの場合は64。
- 宣言は変数名と型名の順: var x int
- 型は省略可
- 初期化
var x int = 100
- 省略記法
x := 100
- 初期値のリテラル値から変数の型が決まる。
- 省略記法
- 初期化しなかった場合、型に応じて初期値(ゼロ値)が与えられる。
- 数値型(int,floatなど): 0
- bool: false
- string: ""(空文字)
- 型変換: 値
v
を型T
に変換する場合T(v)
- 真偽値:
true
,false
- 文字列:
"
(ダブルクォート)で囲んだ文字列"This is a String"
- 整数:
123
- 浮動小数:
0.1234
- 複素数:
1 + 2.3i
- 配列:
[3]T{ t1, t2, t3 }
- ここで
T
は型、t1
、t2
、t3
は型T
の値
- ここで
- スライス:
[]T{ t1, t2, t3 }
var p *int
x := 100
p = &x
*p = 200
- int型のメモリアドレスを指すポインタ変数を定義する際に、型名の前に
*
をつける。 - 変数のメモリアドレスを参照する際に、変数名の前に
&
をつける。 - ポインタ変数が指すメモリアドレスの変数を参照する際に、ポインタ変数の前に
*
をつける。
const
を使って宣言する。const X = 100
func add(x int, y int) int {
return x + y
}
- 戻り値の型を指定する必要がある。
return x, y
のよう複数の値を返すことも可能
func add(x int, y int) (sum int) {
sum = x + y
return
}
- 関数の戻り値には名前をつけることができ、関数内で参照することができる。
- その際、
return
に引数を与えなかった場合の戻り値としてsum
の値が用いられる。
- その際、
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
}
Cのfor文と同様に、
- 初期化
- 条件式
- 後処理
初期化、後処理は省略することができ、さらにセミコロンを略すことで、while
文と同じになる。
sum := 1
for sum < 1000 {
sum += 10
}
を記述する。 条件をなくすことで、無限ループを表現できる。
if x < 0 {
fmt.Println('Negative')
} else if x > 0 {
fmt.Println('Positive')
} else {
fmt.Println('Zero')
}
goのif文はbooleanでしか条件を判断しないので、ゼロ値などで条件式に使うことはできない。
x := "foo"
switch x {
case "foo":
fmt.Println("foo!")
case "bar":
fmt.Println("bar!")
default:
fmt.Println("boo!")
}
goのswitch文は、breakがない。
マッチするcaseで実行された以降のcase文は実行されない。
上の例では、foo!
と出力されるのみ。
func main() {
defer fmt.Println("World")
fmt.Println("Hello,")
}
関数の終了後に事項される関数を登録する。 deferに登録された関数に与えられる引数は、deferを実行した時点で評価される。 deferを複数回実行した時、最後に登録された関数から順に実行される(LIFO)。 IOのクローズや例外処理で利用される。
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 100
v.Y = 200
}
var a [10]int
Goの配列は固定長。
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4] # <= Slice, [ 3, 5, 7 ]
- スライスは配列の部分列で、スライスの要素を変更すると、下の配列の要素も変更される。また、その逆も。
- スライスリテラル:
[]bool{true, false, true}
- 配列
var a [10]int
がある時、スライス式a[low:high]
のそれぞれを省略した場合、配列の先頭および末尾として扱われる。下記の4つの式は等価。a[0:10]
a[:10]
a[0:]
a[:]
make
,append
を使い、動的な配列(スライス)を生成し、要素を追加することができる。
PHPの連想配列、RubyのHashに相当する。
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
// リテラル
m = map[string]Vertex {
"Foo": Vertex{},
"Bar": Vertex{}
}
m["Hoge"] = Vertex{}
delete(m, "Hoge")
elem, ok = m["Bar"]
のように2つの値を返す。
ここで、ok
に有無を表すboolean型の値が入る。
if elem, ok := m["Bar"]; ok {
fmt.Println("Bar's value is ", elem)
} else {
fmt.Println("No Bar's value")
}
func compute(fn func(float64) float64) float64 {
return fn(3)
}
func main() {
sqr := func(x float64) float64 {
return x * x
}
fmt.Println(compute(sqr))
}
- 関数はクロージャーであり、それ自体を値として利用することができる。
- その時の型の定義は、上記の例の
func(float64) float64
のように、引数と戻り値の型を指定する。
- その時の型の定義は、上記の例の
A Tour of Go中のExerciseに出てくるFibonatti関数を返す関数は以下のように書ける。
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
sequence := map[int]int{
0: 0,
1: 1,
}
n := 0
return func() int {
defer func() { n++ }()
if v, ok := sequence[n]; ok {
return v
}
sequence[n] = sequence[n-1] + sequence[n-2]
return sequence[n]
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
Goにはクラスは存在しないが、構造体にメソッドを定義することができる。
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Sqrt() float64 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
func (v *Vertex) setX(x float64) float64 {
v.X = x
return x
}
func main() {
v := Vertex{4, 29}
fmt.Println(v.Sqrt())
p := &Vertex{11, 29}
p.setX(10)
fmt.Println(p.Sqrt())
}
- メソッドの定義は、関数の定義にレシーバーとなる構造体(もしくは構造体のポインタ)を指定することでできる。
- 上の例の
p
のように、構造体のポインタであれば、構造体自体に定義されたメソッドを呼ぶことが出来る。 - Goの関数の引数は値渡しであり、メソッドのレシーバーもまた引数として扱われる。
- 後述するインターフェースの定義によって、構造体もしくは構造体のポインタのどちらかにレシーバーの定義を統一することが推奨される。
- 上の例の
setX
のように構造体に変更を与えるメソッドを定義する場合は、ポインタでないと出来ない。 - また、フィールドを多く持つ構造体の場合は、値渡しのためのコピーにコストがかかる。
- 上の例の
Goのインターフェースは、指定されたメソッドを持つ
type I interface {
M() int
}
type A struct {
X int
}
func (a A) X() int {
return a.X
}
type B struct {
}
func (b *B) X() int {
return 10
}
func main() {
var i I
i = A{100}
i = &B
// i = B fails
}
上の例では、インターフェースIは、「メソッドXを持つ型」として定義されている。
インターフェースIの変数i
に、構造体Aの値は代入できる。
また、構造体BのポインタにメソッドXが定義されているので、構造体Bのポインタ&B
はi
に代入できる。
しかし、構造体Bの値自体はi
に代入できない。
インターフェースは変数の定義時にのみ指定できる。
そのため、実際の値が入るまではnil
を取り、
また、構造体のポインタにメソッドを定義する場合、値を持たないままメソッドを呼ぶことができるため、内部でnil
を適切に取り扱う必要がある。
package main
import "fmt"
type I interface {
M()
}
type S struct {
Str string
}
func (s *S) M() {
if s == nil {
fmt.Println("Nil")
return
}
fmt.Println("Str is ", s.Str)
}
func main() {
var i I
var s *S
i = s
i.M()
i = &S{"Hello"}
i.M()
}
interface{}
は、全ての型と構造体を表すインターフェースとして使える。
しかし、このインターフェースで定義されているべきメソッドは存在していないので、代入することしかできない。
var i interface{}
i = 100
i = "hoge"
インターフェースの変数の値が、実際にどの型なのかを調べる方法として、i.(T)
を使う。
v, ok := i.(T)
iの実際の型がTの時、ok
はtrue
であり、そうでないときはfalse
が入る。
いきなり、i.(T)
を参照し、Tでなかった場合は実行時エラーになる。
また、別の方法として、型スイッチがある。
switch v := i.(type) {
case int: fmt.Println("This is int")
case T: fmt.Println("This is T")
default: fmt.Println("Other")
}
fmt
パッケージが提供するフォーマット出力に対応させるためのインターフェースとしてStringer
インターフェースが定義されている。
fmt.Println
などは、与えられた引数の構造体のString
メソッドから戻ってきた文字列を出力する(JavaのtoString
メソッドと同様)。
package main
import "fmt"
type Vertex struct {
X, Y int
}
func (v Vertex) String() string {
return fmt.Sprintf("(X, Y) = (%v, %v)", v.X, v.Y)
}
func main() {
v := Vertex{7, 29}
fmt.Println(v)
}
Goの特徴として、並行プログラミングを比較的容易に実装できるためのgoroutineやそれをサポートするパッケージがある。
go f(x)
のように、関数f
�を呼ぶことでgoroutineとして関数f
を実行できる。
呼び出し元の処理とは別の処理として並行して実行される。
関数f
の引数x
は、このgo文の時点で評価された値が与えられる。
goroutineとのデータの送受信�にチャネルを使う。
package main
import "fmt"
func Names(c chan string) {
names := []string{"Go", "JavaScript", "PHP"}
for _, name := range names {
c <- name
}
close(c)
}
func main() {
ch := make(chan string)
go Names(ch)
for {
name, ok := <-ch
if ok {
fmt.Println(name)
} else {
break
}
}
ch = make(chan string)
go Names(ch)
for name := range ch {
fmt.Println(name)
}
}
- チャネルの生成は、
make
関数で行う。make(chan string, 100)
のようにチャネルのサイズ(バッファ)を指定できる。
- チャネルの型は、
chan string
のようにチャネルで送受信を行う型を指定する。 - 送信:
ch <- v
- 受信:
v = <-ch
- チャネルの送受信の評価で処理は一旦ブロックされ、値をチャネルから受信(または送信)できるようになったら時点で再開される。
- チャネルは送信側(上の例だと関数
Names
)のみチャネルをクローズすることができる。- 受信側では、
name, ok := <-ch
のようにチャネルが閉じているかどうかを真偽値として受け取ることができる。 - また
range ch
のようにrange
を使う場合は、送信側がclose
を実行しないと実行時エラーになる。
- 受信側では、
複数のチャネルを利用する場合に、select
を使って制御できる。
package main
import (
"fmt"
"time"
)
func Greeting(names chan string, control chan bool) {
for {
select {
case name := <-names:
fmt.Printf("%v DEATH!\n", name)
case <-control:
break
default:
fmt.Println("... Waiting")
time.Sleep(500 * time.Millisecond)
}
}
}
func main() {
names := []string{"YUIMETAL", "MOAMETAL", "SU-METAL"}
ch := make(chan string)
c := make(chan bool)
go Greeting(ch, c)
for _, name := range names {
ch <- name
time.Sleep(4 * time.Second)
}
c <- true
}
Go v1.12から標準で依存管理の仕組みとしてGo Modulesが導入された。 モジュールとはGoパッケージの集まりであり、GitHubなどソースコード管理ツールから公開配布される。
開発しているモジュールが依存するモジュールのパスを記述する。 Go Modulesの依存解決がセマンティックバージョニングに基づいているため、モジュールのバージョニングもこれに従うことが求められる。
go.mod
ファイルの例を以下に示す。
module M
require (
A v1
B v1.0.0
C v1.2.3
)
exclude C v1.2.3
module
はモジュール名とバージョンを指定する。
require
は、モジュールMが依存するモジュールのパスとバージョンを指定する。
exclude
は、require
で指定された依存モジュールの中で、使用しないバージョンを指定する。
上の例の場合、
モジュールMは、以下のモジュールに依存している。
モジュールA v1.0.0以降
モジュールB v1.0.0以降
モジュールC v1.2.3以降、且つv1.2.3以外
実際にどのバージョンになるかは、go mod
コマンドを実行し、モジュールを取得する時点で上記の条件を満たすものに決まる。
開発するGoモジュールのワークスペースに移動し、go mod init
コマンドを実行する。
すると、go.mod
ファイルが生成され、依存関係を記述するための準備が完了する。
go.mod
に依存関係を記述した後、go.mod
と同じディレクトリ上へ移動し、go mod download
を実行する。
すると、go.mod
に基づいて依存モジュールの依存解決が行われ、該当のバージョンのダウンロードが実施される。
実際にどのバージョンをダウンロードしたのかは、go.sum
に記録される。
- Go Modulesの概要とGo1.12に含まれるModulesに関する変更 #golangjp #go112party - My External Storage
- モジュール対応モードへの移行を検討する — プログラミング言語 Go | text.Baldanders.info
- go - The Go Programming Language
- research!rsc: Minimal Version Selection (Go & Versioning, Part 4)
- 言語
- IDE
- Web framework
- Rails、Sinatra、Rackみたいなものを探してみる。
- Qiitaで探して、軽く作ってみる。https://qiita.com/loftkun/items/1a9951d1864bebdc51e1
- パッケージマネージャ
- bundler, gem みたいなもの探す。 -> Go modules
- パッケージ配布
- rubygems.org みたいなものを探す。
- テストフレームワーク
- test-unit 、RSpec みたいなもの
- デプロイ
- デプロイの方法
- ホスティングサービス
- とりあえず動かせる場所としてよく使われてそうなもの(Heroku?