A Tour of Go メモ ~Packages, variables, and functions~

## はじめに

Go の勉強のため、[A Tour of Go](https://go-tour-jp.appspot.com/basics/1)に取り組んでいる
今回は`Packages, variables, and functions`章について、学んだことを記していく

まとめ記事は[こちら](https://qiita.com/eyuta/items/77ac58e4d9141898c733)

## 使えそうなスニペット

※筆者は VSCode を使用

- スニペットは最初の一文字を入力するだけで予測変換に出てくるので、全部を入力する必要はない
- また、文字を飛ばしても良い
- 以下の例でいうと、`pm`と入力しても`pkgm`が予測変換に出る

`pkgm` -> `package main`
`fm` -> `func main(){ }`
`func` -> `func (){ }`
`fp` -> `fmt.Println("")`
`ff` -> `fmt.Printf("", var)`
`iferr` -> `if err != nil { return nil, err}`

## ページごとの補足

`A Tour of Go`を進めていく中で、疑問に思ったことをまとめた

### Packages

#### Import する package 名は、Import Path の最後の要素になる

- Ex: `math/rand` -> `rand`

同じ名前のパッケージをインポートしたい場合は、Package Name を指定する
また、Package Name にドット(`.`)を指定すると、修飾子なしにメソッドにアクセスできる

```go
// Import declaration          Local name of Sin

import   "lib/math"         // math.Sin
import m "lib/math"         // m.Sin
import . "lib/math"         // Sin
```

Ref. [The Go Programming Language Specification](https://golang.org/ref/spec)

#### `math/rand`の使い方

`math/rand`はシード値が同じであれば同じ疑似乱数を返すため、実行するたびに値を変更したければ`Seed`メソッドを都度呼ぶ必要がある
また、`Seed`メソッドの引数に`time.Now().UnixNano()`を使うことで、疑似乱数が作りやすくなる。

```go
import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	fmt.Println(rand.Intn(10)) // 1 固定
	rand.Seed(10)
	fmt.Println(rand.Intn(10)) // 4 固定
	rand.Seed(time.Now().UnixNano())
	fmt.Println(rand.Intn(10)) // 毎回変わる
}
```

ただ、より安全性の高い乱数を作りたい場合は`crypto/rand`を使用する

```go
package main

import (
	"crypto/rand"
	"fmt"
	"math/big"
)

func main() {
	n, err := rand.Int(rand.Reader, big.NewInt(10))
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(n)
}
```

Ref. [Go の math/rand と crypto/rand](https://qiita.com/crifff/items/b116e6235fedcd18e0de)

### Imports

複数`import`する際は Factored Import Statement で記述する
(Factored は直訳で因数分解、意訳でグループ化らしい)
`import`に限らず、`var`, `const`で複数定義する際も、これを用いる
ちなみに、1 つだけ定義した場合もこのスタイルで書ける模様
(フォーマッタに添削されないということは、割とスタンダードなのだろうか)

```go
import (
	"fmt"
	"math"
)

func main() {
	const (
		x = 1
		y = 2
	)
	var (
		z = math.Pi
	)
	fmt.Println(z)
}
```

### Exported names

大文字の名前はエクスポートされ、小文字はされない

```foo.go
package foo

func Test() string {
	return "Success"
}
func test() string {
	return "Failure"
}

const (
	CONSTANT = 1
	constant = 2
)
```

```main.go
package main

import (
	"./foo"
	"fmt"
)

func main() {
	fmt.Println(foo.Test())
	fmt.Println(foo.CONSTANT)

	// Error: cannot refer to unexported name foo.test
	// Error: cannot refer to unexported name foo.constant
	fmt.Println(foo.test())
	fmt.Println(foo.constant)
}
```

ちなみに、ファイル分割の方法は以下が参考になった
Ref. [Go 言語の package の作り方: 長くなったコードを別ファイルに切り出す方法](https://qiita.com/suin/items/f4ad02e4123c8a3c75eb)

### Functions

C 言語や Java 等とは異なり、`変数名 型名`の順に記述する
理由は[こちら](https://blog.golang.org/declaration-syntax)
※和訳は、[こちら](https://qiita.com/m0a/items/2b03b189d746ae231756)がわかりやすかった

一言で言えば、「こっちのほうが可読性が良いから」

### Multiple results

複数の戻り値を返すことができる
戻り値の一部を使わない場合は、受け取る変数名を`_`にすれば良い
こうしないとコンパイル時に`declared but not used`とエラーが出る

```go
package main

import (
	"fmt"
)

func swap(x, y string) (string, string) {
	return y, x
}

func main() {
	a, _ := swap("Hello", "World")
	fmt.Println(a)
}
```

### Basic Types

#### rune(ルーン) とは

`'`で定義される文字列であり、Unicode のコードポイントを指す。中身は int32 の alias である
コードポイントについては[こちら](https://qiita.com/seihmd/items/4a878e7fa340d7963fee)が分かりやすい

#### rune と string の違い

※以下の記事を参考にした

- [String と Rune](https://text.baldanders.info/golang/string-and-rune/)
- [Strings, bytes, runes and characters in Go](https://blog.golang.org/strings)

実は、string 型は、値を Byte 配列で格納している
そのため、単純に for 文で回すと以下のようになる

```go
	x := "aあ"
	for i := 0; i < len(x); i++ {
		fmt.Printf("% x", x[i])
  }
  // 61 e3 81 82

	for i := 0; i < len(x); i++ {
		fmt.Printf("% v", x[i])
	}
  // 97 227 129 130
```

１文字を１文字として扱うには、[for range](https://www.spinute.org/go-by-example/range.html)構文を使う必要がある
for range 構文で string を回すと、rune が取れる

```go
	x := "aあ"
	for _, y := range x {
		fmt.Printf("% x", y)
  }
  //  61 3042

	fmt.Println("")
	for _, y := range x {
		fmt.Printf(" %c", y)
	}
  // a あ
```

※`%c`は整数(コードポイント)に対応する文字を返す
Ref. [fmt.Printf なんかこわくない](https://qiita.com/rock619/items/14eb2b32f189514b5c3c)

### Zero Values

変数に初期値が与えられないとゼロ値が与えられる
逆に、変数にゼロを与えた場合は、表記によって型が変わる

```go
	fmt.Printf("%T", 0)   // int
	fmt.Printf("%T", 0.0) // float64
```

## 蛇足

ルーンって型名を使ってるだけで、Go 言語が大好きになった
以下を忘れないようにしよう
(キャスニキの呪文のコードポイントも調べようとしたけど、長すぎるので断念……)

```go
	ansz := 'ᚨ' // アンサズ: 発火のルーン
	fmt.Printf("%d, %x", ansz, ansz) // 5800, 16a8
```