Last active
April 3, 2018 14:22
-
-
Save varlal/4d653726bc7de3e4ae343b0627a1f599 to your computer and use it in GitHub Desktop.
a_tour_of_go_list
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Goのプログラムはpackageで構成 | |
// importでパッケージを読み込み | |
package main | |
// 規約:パッケージ名はインポートパスの最後の要素と同じ名前 | |
// 例えば、math/randをインポートすると、package randを読み込む | |
import "math/rand" | |
// 1行づつimport | |
import "fmt" | |
import "math" | |
// まとめてimport factored import statement | |
import ( | |
"fmt" | |
"math" | |
) | |
// 大文字はExported names(パブリック(パッケージ外に公開している)変数) | |
fmt.Println(math.Pi) | |
// 型の宣言(以下2つは同等) | |
x int , y int | |
x, y int | |
// 複数の引数・戻り値を指定可 | |
func swap(x, y string) (string, string) { | |
return y, x | |
} | |
func main() { | |
a, b := swap("hello", "world") | |
fmt.Println(a, b) // world hello | |
} | |
// Named return value 戻り値に名前を付けることができる | |
// 名前を付けた戻り値がある場合、returnステートメントに何も書かなくても戻り値を返す | |
// "Naked return"という。しかし、短い関数でのみ利用すべき。長い関数で使うと読みやすさ( readability )に悪影響 | |
func split(sum int) (x, y int) { | |
x = sum * 4 / 9 | |
y = sum - x | |
return | |
} | |
func main() { | |
fmt.Println(split(9)) // 4 5 | |
} | |
// varステートメントは変数を宣言 | |
var c, python, java bool | |
func main() { | |
var i int | |
fmt.Println(i, c, python, java) // 0 false false false | |
} | |
// 変数の初期化:初期化した場合、型を省略できる | |
var i, j int = 1, 2 | |
var c, python, java = true, false, "no!" | |
// 関数内では、varの代わりに:=の定義式を用いて、暗黙的な型宣言ができる | |
k := 3 | |
c, python, java := true, false, "no!" | |
// 基本型(組み込み型:basic type) | |
// bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex64 complex128 | |
// byte ⇒ uint8 の別名 | |
// rune ⇒ int32 の別名 | |
var ( | |
ToBe bool = false | |
MaxInt uint64 = 1<<64 - 1 | |
z complex128 = cmplx.Sqrt(-5 + 12i) | |
) | |
func main() { | |
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe) | |
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt) | |
fmt.Printf("Type: %T Value: %v\n", z, z) | |
} | |
// 初期値を与えずに宣言すると、ゼロ値:ZERO Valueが入る | |
// 数値型(int,floatなど): 0 | |
// bool型: false | |
// string型: "" (空文字列( empty string )) | |
func main() { | |
var i int | |
var f float64 | |
var b bool | |
var s string | |
fmt.Printf("%v %v %v %q\n", i, f, b, s) //0 0 false "" | |
} | |
// 型変換 Type Conversions | |
// 変数 v 、型 T があった場合、 T(v) は、変数 v を T 型へ変換 | |
// C言語とは異なり、Goでの型変換は明示的な変換が必要 | |
var x, y int = 3, 4 | |
var f float64 = math.Sqrt((x*x + y*y)) //ここはエラーになる | |
// for文 | |
// 初期化と後処理ステートメントの記述は任意 | |
// セミコロン(;)を省略することもできる | |
func main() { | |
sum := 0 | |
for i := 0; i < 10; i++ { | |
sum += i | |
} | |
fmt.Println(sum) | |
} | |
func main() { | |
sum := 1 | |
for ; sum < 1000; { | |
sum += sum | |
} | |
fmt.Println(sum) | |
} | |
func main() { | |
sum := 1 | |
for sum < 1000 { | |
sum += sum | |
} | |
fmt.Println(sum) | |
} | |
// infinite loop 無限ループ | |
func main() { | |
for { | |
} | |
} | |
// if文 | |
func sqrt(x float64) string { | |
if x < 0 { | |
return sqrt(-x) + "i" | |
} | |
return fmt.Sprint(math.Sqrt(x)) | |
} | |
func main() { | |
fmt.Println(sqrt(2), sqrt(-4)) | |
} | |
// if文は、forと同様に条件の前に、評価するための簡単なステートメントを書くことができる | |
// ここで宣言された変数は、 if のスコープ内だけで有効 | |
func pow(x, n, lim float64) float64 { | |
if v := math.Pow(x, n); v < lim { | |
return v | |
} | |
return lim | |
} | |
func main() { | |
fmt.Println( | |
pow(3, 2, 10), // 9 | |
pow(3, 3, 20), // 20 | |
) | |
} | |
// pointers | |
// Goはポインタを扱います。 ポインタは値のメモリアドレスを指します。 | |
// 変数 T のポインタは、 *T 型で、ゼロ値は nil です。 | |
// var p *int | |
// & オペレータは、そのオペランド( operand )へのポインタを引き出します。 | |
// i := 42 | |
// p = &i | |
// * オペレータは、ポインタの指す先の変数を示します。 | |
// fmt.Println(*p) // ポインタpを通してiから値を読みだす | |
// *p = 21 // ポインタpを通してiへ値を代入する | |
// これは "dereferencing" または "indirecting" としてよく知られています。 | |
func main() { | |
i, j := 42, 2701 | |
p := &i // point to i | |
fmt.Println(*p) // read i through the pointer //42 | |
*p = 21 // set i through the pointer | |
fmt.Println(i) // see the new value of i // 21 | |
p = &j // point to j | |
*p = *p / 37 // divide j through the pointer | |
fmt.Println(j) // see the new value of j // 73 | |
} | |
// structs 構造体 | |
// struct (構造体)は、フィールド( field )の集まり | |
// structのフィールドは、ドット( . )を用いてアクセス | |
// structのポインタがある場合、フィールドへは略式記述できる (*p).X ⇒ p.X | |
type Vertex struct { | |
X int | |
Y int | |
} | |
func main() { | |
v := Vertex{1, 2} | |
v.X = 4 | |
fmt.Println(v.X) | |
} | |
func main() { | |
v := Vertex{1, 2} | |
p := &v | |
p.X = 1e9 | |
fmt.Println(v) // {1000000000 2} | |
} | |
// structリテラルは、フィールドの値を列挙することで新しいstructの初期値の割り当てを示している。一部だけ列挙もできる。 | |
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 | |
// [n]T 型は、型 T の n 個の変数の配列( array )を表します。 | |
// 以下は、intの10個の配列を宣言しています: | |
// var a [10]int | |
// 配列の長さは、型の一部分です。ですので、配列のサイズを変えることはできません | |
// Slices | |
// 配列は固定長です。一方で、スライスは可変長です。より柔軟な配列と見なすこともできます。 実際には、スライスは配列よりもより一般的です。 | |
// 型 []T は 型 T のスライスを表します。 | |
// コロンで区切られた二つのインデックス low と high の境界を指定することによってスライスが形成されます: | |
// a[low : high] | |
// これは最初の要素を含む half-open レンジを選択しますが、最後の要素は省かれます。 | |
// 次の式は a の要素の内 1 から 3 を含むスライスを作ります。 | |
// a[1:4] | |
func main() { | |
primes := [6]int{2, 3, 5, 7, 11, 13} | |
var s []int = primes[1:4] | |
fmt.Println(s) //[3 5 7] | |
} | |
// スライスは配列への参照のようなものです。 | |
// スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示している | |
// スライスの要素を変更すると、その元となる配列の対応する要素が変更 | |
func main() { | |
names := [4]string{ | |
"John", | |
"Paul", | |
"George", | |
"Ringo", | |
} | |
fmt.Println(names) // [John Paul George Ringo] | |
a := names[0:2] | |
b := names[1:3] | |
fmt.Println(a, b) // [John Paul] [Paul George] | |
b[0] = "XXX" | |
fmt.Println(a, b) // [John XXX] [XXX George] | |
fmt.Println(names) // [John XXX George Ringo] | |
} | |
// スライスのリテラルは長さのない配列リテラル | |
func main() { | |
s := []struct { | |
i int | |
b bool | |
}{ | |
{2, true}, | |
{3, false}, | |
{5, true}, | |
{7, true}, | |
{11, false}, | |
{13, true}, | |
} | |
fmt.Println(s) //[{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}] | |
} | |
// Maps | |
// map はキーと値とを関連付けます(マップします)。 | |
// マップのゼロ値は nil です。 nil マップはキーを持っておらず、またキーを追加することもできません。 | |
// make 関数は指定された型の、初期化され使用できるようにしたマップを返します。 | |
type Vertex struct { | |
Lat, Long float64 | |
} | |
var m map[string]Vertex | |
func main() { | |
m = make(map[string]Vertex) | |
m["Bell Labs"] = Vertex{ | |
40.68433, -74.39967, | |
} | |
fmt.Println(m["Bell Labs"]) //{40.68433 -74.39967} | |
} | |
// 関数も変数です。他の変数のように関数を渡すことができます。 | |
// 関数値( function value )は、関数の引数に取ることもできますし、戻り値としても利用できます。 | |
func compute(fn func(float64, float64) float64) float64 { | |
return fn(3, 4) | |
} | |
func main() { | |
hypot := func(x, y float64) float64 { | |
return math.Sqrt(x*x + y*y) | |
} | |
fmt.Println(hypot(5, 12)) //13 | |
fmt.Println(compute(hypot)) //5 | |
fmt.Println(compute(math.Pow)) //81 | |
} | |
// Function closures | |
// Goの関数は クロージャ( closure ) です。 クロージャは、それ自身の外部から変数を参照する関数値です。 | |
// この関数は、参照された変数へアクセスして変えることができ、その意味では、その関数は変数へ"バインド"( bind )されています。 | |
// 例えば、 adder 関数はクロージャを返しています。 各クロージャは、それ自身の sum 変数へバインドされます。 | |
func adder() func(int) int { | |
sum := 0 | |
return func(x int) int { | |
sum += x | |
return sum | |
} | |
} | |
func main() { | |
pos, neg := adder(), adder() | |
for i := 0; i < 10; i++ { | |
fmt.Println( | |
pos(i), | |
neg(-2*i), | |
) | |
} | |
} | |
// Goには、クラス( class )のしくみはありませんが、型にメソッド( method )を定義できます。 | |
// メソッドは、特別なレシーバ( receiver )引数を関数 | |
// Abs メソッドは v という名前の Vertex 型のレシーバを持つことを意味 | |
// メソッドとは、レシーバ引数を伴う関数 | |
// Aはメソッド、Bは通常の関数として記述 | |
type Vertex struct { | |
X, Y float64 | |
} | |
func (v Vertex) Abs() float64 { // A | |
return math.Sqrt(v.X*v.X + v.Y*v.Y) | |
} | |
func Abs(v Vertex) float64 { // B | |
return math.Sqrt(v.X*v.X + v.Y*v.Y) | |
} | |
func main() { | |
v := Vertex{3, 4} | |
fmt.Println(v.Abs()) | |
} | |
// 型にメソッドを実装していくことによって、インタフェースを実装(満た)します。 | |
// インタフェースを実装することを明示的に宣言する必要はありません( "implements" キーワードは必要ありません)。 | |
type I interface { | |
M() | |
} | |
type T struct { | |
S string | |
} | |
// This method means type T implements the interface I, | |
// but we don't need to explicitly declare that it does so. | |
func (t T) M() { | |
fmt.Println(t.S) | |
} | |
func main() { | |
var i I = T{"hello"} | |
i.M() | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment