Skip to content

Instantly share code, notes, and snippets.

@varlal
Last active April 3, 2018 14:22
Show Gist options
  • Save varlal/4d653726bc7de3e4ae343b0627a1f599 to your computer and use it in GitHub Desktop.
Save varlal/4d653726bc7de3e4ae343b0627a1f599 to your computer and use it in GitHub Desktop.
a_tour_of_go_list
// 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