A Tour of goが長くてどこまでやったかわからなくなるので自分用まとめ
- パッケージ名はインポートパスの最後の要素と同じの名前
- goのメソッド名は最初の文字が大文字で始まる場合にpublic扱いで、それ以外はprivate(Exported names)
- 関数の引数は、変数名の後ろに型名を書く(Functions)
func add(x int, y int) int {
return x + y
}
- 関数の2つ以上の引数が同じ型である場合は、最後の型を残して省略出来る(Functions)
func add(x, y int) int {
return x + y
}
- 関数は複数の戻り値を返す事が出来る(Functions)
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
}
- 返り値となる変数に名前をつけることができる。型を書くとI/Oが1行にまとまって見やすそう(Named return values)
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
- var宣言で型は省略出来る(Variables)
var c, python, java = true, false, "no!"
import
と同様に、まとめて宣言可能
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
- var宣言のかわりに、
:=
を使う事もできる(Variables)
c, python, java := true, false, "no!"
Go言語の基本型
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 の別名
rune // int32 の別名
// Unicode のコードポイントを表す
float32 float64
complex64 complex128
Goの型変換(Type conversions)
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
fmt.Printf("%T %T %T",i, f, u) // int float64 uint
定数(Constants)
const World = "世界"
fmt.Println("Hello", World) // Hello 世界
for
// 基本
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
// 条件式以外は省略可(条件式を省略すれば無限ループになる)
sum := 1
for ; sum < 1000; {
sum += sum
}
// Goでのwhileはforで書ける
sum := 1
for ; sum < 1000; {
sum += sum
}
if
func pow(x, n, lim float64) float64 {
// ifの条件式の前には簡単なステートメントを書ける
if v := math.Pow(x, n); v < lim {
return v
}
return lim
// return v // ただし、if-elseのスコープ外では無効(これはundefined: v になる)
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
switch
breakは書かなくても自動でされる。代わりにbreakしたくない場合は、fallthrough
を書く
条件文のないswitchは、if-then-else構造をシンプルに表現出来る
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
defer
defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させる
defer へ渡した関数は LIFO(last-in-first-out) の順番で実行される
func main() {
defer fmt.Println("world")
var lang = "golang"
defer fmt.Println(lang)
lang = "ruby"
fmt.Println("hello") // hello golang world と出力される
}
Pointers
func main() {
i, j := 42, 2701
p := &i
fmt.Println(*p) // 42
*p = 21
fmt.Println(i) // 21
p = &j
*p = *p / 37
fmt.Println(j) // 73
}
Structs(構造体)
Structのフィールドには、ドット( . )でアクセスする
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
もしくはポインタでアクセス
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
Struct Literals
読んでて使い所がよくわからなかったけどのちほど調べる
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex
)
func main() {
fmt.Println(v1, p, v2, v3) // {1 2} &{1 2} {1 0} {0 0}
}
Arrays
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1]) // Hello World
fmt.Println(a) // [Hello World]
}
Slices
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println("s ==", s) // s == [2 3 5 7 11 13]
for i := 0; i < len(s); i++ {
fmt.Printf("s[%d] == %d\n", i, s[i])
}
}
Slices of Slices
スライスには任意の型を収めることができ、他のスライスを入れることもできる
func main() {
// Create a tic-tac-toe board.
game := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// The players take turns.
game[0][0] = "X"
game[2][2] = "O"
game[2][0] = "X"
game[1][0] = "O"
game[0][2] = "X"
printBoard(game)
}
func printBoard(s [][]string) {
for i := 0; i < len(s); i++ {
fmt.Printf("%s\n", strings.Join(s[i], " "))
}
}
/*
X _ X
O _ _
X _ O
*/
Slicing slices
s[lo:hi] // lo から hi-1 までの要素のスライスを返す
s[lo:lo] // 空のスライスとなる
s[lo:lo+1] // 1つの要素を持つスライスとなる
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println("s ==", s)
fmt.Println("s[1:4] ==", s[4:4]) // []
// missing low index implies 0
fmt.Println("s[:3] ==", s[:3]) // [2 3 5]
// missing high index implies len(s)
fmt.Println("s[4:] ==", s[4:]) // [11 13]
Making slices
// 長さ5のスライスを生成
a := make([]int, 5) // [0 0 0 0 0]
// 3番目の引数に、スライスの容量を指定出来る
b := make([]int, 0, 5) // []
Nil slices
スライスのゼロ値はnil
var z []int
fmt.Println(z, len(z), cap(z))
if z == nil {
fmt.Println("nil!")
}
Adding elements to a slice
スライスへ新しい要素を追加するには、append
を使用。
var a []int
fmt.Printf("%s", a);
var a []int
fmt.Printf("%d\n",a) // []
a = append(a, 0)
fmt.Printf("%d\n",a) // [0]
a = append(a, 2, 3, 4)
fmt.Printf("%d\n",a) // [0 2 3 4]
Range
range
は反復毎に2つの変数を返す。1つ目の変数はインデックスで、2つ目の変数は値。(foreach的な感じ)
変数の部分に_
(アンダーバー)を指定する事で、値は捨てる事が出来る
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2[%d] = %d\n", i, v)
}
for _, v := range pow {
fmt.Printf("2[%d] = %d\n", i, v) // iは捨てているのでエラーになる。(vだけならばエラーにならない)
}
Maps
map[(keyの型)](valueの型)
という感じで書く
mapはmake
で作成する必要がある
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
Map literals
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
fmt.Println(m) // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
mapに渡すトップレベルの型が単純な型である場合、型は省略できる
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
Mutating Maps
// 要素の挿入・更新
m[key] = elem
// 要素の取得
elem = m[key]
// 要素の削除
delete(m, key)
// キーに対する要素が存在するかどうか、2つ目の値で確認出来る(変数okはboolで存在すればtrue)
// mapにkeyが存在しない場合、elemはmapの要素の型のゼロ値になる
elem, ok = m[key]
// elemとokが未宣言であれば、 := で省略できる
elem, ok := m[key]
Function closures
func adder() func(int) int {
sum := 0
fmt.Println("adder")
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos := adder()
for i := 0; i < 10; i++ {
fmt.Println(pos(i))
}
}
// adder
// 0
// 1
// 3
// 6
// 10
Methods
Goにはclassのしくみはないが、struct型にMethodを定義出来る((v *Vertex)
の部分を「レシーバ」と言う)
type Vertex struct {
X, Y float64
}
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()) // 5
}
Interfaces
interface型は、Methodの集まりで定義。
type Abser interface {
Abs() float64
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat implements Abser
a = &v // a *Vertex implements Abser
// In the following line, v is a Vertex (not *Vertex)
// and does NOT implement Abser.
a = v /* Absは、Vertexではなく*Vertexの定義なので、ここでエラーになる */
fmt.Println(a.Abs())
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 { // ←レシーバを*VertexからVertexに変更するとエラーがでなくなる
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Stringers
よく使われているinterfaceの1つに、fmt
パッケージに定義されているStringer
がある
type Stringer interface {
String() string
}
Stringer インタフェースは、stringとして表現することができる型です。 fmt パッケージ(と、多くのパッケージ)では、変数を文字列で出力するためにこのインタフェースがあることを確認します。
package main
import "fmt"
// 構造体
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) // Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)
}
Errors
Go言語では例外という概念はなく、error
型という変数が用意されている
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err) // at 2009-11-10 23:00:00 +0000 UTC, it didn't work
}
}
その他
ここからは、実際に触ってみる途上で試してみた事とかのメモ
- importはディレクトリしか指定出来ない(ファイル単体をimportしようとするとエラーになる)