🐕

A Tour of Goを試す

2020/11/03に公開

"A Tour of Go"のBasicsを読んだメモ。

package

Gopackageで構成され、mainパッケージから開始される。

import

facotred import statement

パッケージのインポートをグループ化

import(
    "fmt"
    "math"
)

// 下記と同じ
import "fmt"
import "math"

exported name

パッケージをインポートすると、エクスポート(公開)している名前(大文字で始まる名前)を参照できる。
エクスポートされていないもの(小文字で始まる名前)は外部のパッケージからアクセス不可。

function

  • 変数名の後ろには型名を書く
  • 2つ以上の引数が同じ型の場合は最後の型以外を省略できる
x, y int // <--- x int, y int
  • 複数の戻り値を返すことが可能
  • 戻り値の変数に名前を付けられる
    • 名前付き戻り値の変数を使うとreturn文に何も書かなくて良い(naked return

変数

  • varで宣言
  • まとめて複数宣言可能。型は最後
  • varはパッケージ、関数で利用
var a, b, c int
  • 宣言と同時に初期化子を与える。型を省略できる
var a, b = 1, 2

short variable declaration

関数の中でvarの代わりに:=の代入文で暗黙的な型宣言ができる。
関数の外では不可

factored宣言

var (
	ToBe   bool       = false
	MaxInt uint64     = 1<<64 - 1
	z      complex128 = cmplx.Sqrt(-5 + 12i)
)

基本型(組み込み型)

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

rune // int32 の別名
     // Unicode のコードポイントを表す

float32 float64

complex64 complex128

ゼロ値

変数に初期値を与えずに宣言するとゼロ値が設定される。

  • 数値型(int,floatなど): 0
  • bool型: false
  • string型: ""(空文字列)

型変換

T(v)で変数vをT型に変換。
型変換しないとエラーになる。

var o int = 42
var p float64 = o
// ./prog.go:15:6: cannot use o (type int) as type float64 in assignment

型推論

明示的に型を指定せずに変数を宣言した場合(:=var =)、変数の型は右側の変数の型から型推論される。

定数

  • constキーワードを使って宣言する
  • 英数は文字、文字列、数値のみで利用可能
  • 定数は:=宣言不可
  • 数値の定数は、高精度な値(?)

For文

  • 初期化ステートメント、条件式、後処理ステートメント
  • セミコロン(;)で区切る。
  • () は不要
  • 初期化ステートメントと後処理ステートメントは省略可
for i := 0; i < 10; i++  { /* process */ }
  • セミコロン(;)は省略可。いわゆるwhile文と同じ
for sum < 100 { /* process */ }
  • ループ条件を省略すると無限ループ
for { /* process */ }

if文

() は不要

評価式

  • 条件の前に評価式を書くことができる
  • elseブロックでも宣言されて変数を利用可能

演習(平方根)

こんな感じでいいのかな?

package main

import (
	"fmt"
)

func Sqrt(x float64) float64 {
//	z := 1.0
	z := x

	end := z
	count := 0

//	for i := 1; i <= 10; i++ {
	for i := 1; ; i++ {
		z -= (z*z - x) / (2*z)
		count = i

//		if end == z { break }
		if f := end - z; f < 0.001 { break }

		end = z
	}
	fmt.Println("count :", count, ", over 10 :", count > 10)

	return z
}

func main() {
	fmt.Println(Sqrt(2))
}

Switch文

  • 合致したcaseのみ実行(break不要)
  • 合致したら停止(自動的にbreakする)
  • caseで合致させるものは何でもよい(?)
switch value {
    case "foo":
        // process
    default:
        // process
}
  • 条件なしはswitch trueと書くことと同じ
switch {
    case i > 0:
        // process
    default:
        // process
}

defer文

  • deferへ渡した関数の引数はすぐに評価され、関数自体は呼び出し元の関数が終わる(returnされる)まで実行されない
  • 呼び出しはスタックされ、LIFOの順番で実行される

ポインタ

  • ポインタは値のメモリアドレスを指す
  • 変数Tのポインタは、*T型で、ゼロ値はnil
  • &オペレータは、そのオペランドへのポインタを引き出す
  • *オペレータは、ポインタの指す先の変数を示す

struct(構造体)

  • structはフィールドの集まり
  • structリテラルはフィールドの値を列挙して初期化。フィールド名を明記することも可能。フィールドの一部でも良い。
  • フィールドはドット(.)でアクセス。またstructのポイント経由でアクセス可能。
type Vertex struct {
    X int
	Y int
}
v := Vertex{1, 2}
// v2 = Vertex{X: 1, Y: 2}
v.X = 4

// pointer
p := &v
p.X = 1e9

Array(配列)

[n]T型は、型Tのn個の変数の配列を表します。

  • 配列は固定長。配列のサイズを変えることはできない
var array [2]string
var array = [2]string{"Hello", "World"}

Slice

型[]Tは型Tのスライスを表します。

  • スライスは可変長
  • スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示しています。
  • スライスの要素を変更すると、その元となる配列の対応する要素が変更されます。
  • 同じ元となる配列を共有している他のスライスは、それらの変更が反映されます。
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
// var s = []int{3, 5, 7}

default

  • 既定値を代わりに使用することで上限または下限を省略することができます。
    既定値は下限が0で上限はスライスの長さです。

length & capacity

スライスは長さ( length )と容量( capacity )の両方を持っています。
スライスの長さは、それに含まれる要素の数です。
スライスの容量は、スライスの最初の要素から数えて、元となる配列の要素数です。
スライスsの長さと容量はlen(s)cap(s)という式を使用して得ることができます。

再スライス

スライスの長さを伸ばすことができる

nilスライス

  • スライスのゼロ値はnil
  • nilスライスは0の長さと容量を持っている

スライスのスライス

スライスは、他のスライスを含む任意の型を含むことができます。

スライスの作成

組み込みのmake関数でスライスを作成

s := make([]int, 5)

要素の追加

組み込みのappend関数でスライスへ新しい要素を追加

s = append(s, 2, 3, 4)

range

  • for文で反復処理をするために使う
  • インデックスと要素のコピーの2つの変数を返す
  • インデックスや値は_へ代入して捨てることができる
for index, value := range pow {
    // process
}

Map

  • mapはキーと値とを関連付ける
  • ゼロ値はnil
  • make関数で作成
v := make(map[int]string)
v[0] = "Foo"

演習(Map)

import (
	"golang.org/x/tour/wc"
	"strings"
)

func WordCount(s string) map[string]int {
	results := map[string]int{}

	for _, value := range strings.Fields(s) {
		if v, ok := results[value]; ok {
			results[value] = v + 1
		} else {
			results[value] = 1
		}
	}
	return results
}

func main() {
	wc.Test(WordCount)
}

関数値(function value)

  • 関数は他の関数の引数や戻り値として利用できる
  • 関数はクロージャ(closure)

演習(フィボナッチ数)

再帰的関数の実装がわからず。

func fibonacci() func() int {
	r := [2]int{0, 1}
	i := 0

	return func() int {
		defer func() { i++ }()

		switch {
			case i == 0:
				return 0
			case i == 1:
				return 1
			default:
				v := r[0] + r[1]
				r[0] = r[1]
				r[1] = v
				return v
		}
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

Discussion