▶ 技術めも
Go 言語
基本
// 実行
$ go run test.go
// コンパイル
$ go build test.go
// フォーマット(コード規約)
$ go fmt test.go
// ドキュメント(パッケージ)
$ godoc fmt
// ブラウザでドキュメント
$ godoc -http=":3000"
→ http://localhost:3000
// プログラム開始位置
package main
func main() {
// first start
}
import (
f "fmt"
_ "github.com/wdpress/gosample"
. "strings"
)
組み込み型
uint8 符号なし 8-ビット 整数 (0 to 255)
uint16 符号なし 16-ビット 整数 (0 to 65535)
uint32 符号なし 32-ビット 整数 (0 to 4294967295)
uint64 符号なし 64-ビット 整数 (0 to 18446744073709551615)
int8 符号あり 8-ビット 整数 (-128 to 127)
int16 符号あり 16-ビット 整数 (-32768 to 32767)
int32 符号あり 32-ビット 整数 (-2147483648 to 2147483647)
int64 符号あり 64-ビット 整数 (-9223372036854775808 to 9223372036854775807)
float32 IEEE-754 32-ビット 浮動小数値
float64 IEEE-754 64-ビット 浮動小数値
complex64 float32の実数部と虚数部を持つ複素数
complex128 float64の実数部と虚数部を持つ複素数
byte uint8の別名(エイリアス)
rune int32の別名(エイリアス)
uint 32 または 64 ビット
int uintと同じサイズ
uintptr ポインタの値をそのまま格納するのに充分な大きさの符号なし整数
error エラーを表すインターフェイス
変数
var message string = "hello world"
func main() {
fmt.Println(message)
}
宣言
var foo, bar, buz string = "foo", "bar", "buz"
var (
a string = "aaa"
b = "bbb"
c = "ccc"
)
func main() {
// 関数内部での宣言と初期化
var message1 string = "hello world"
message2 := "hello world"
// 定数
const Hello string = "hello !!!"
}
省略形式の時は少なくともひとつ新しい変数であれば、他は再宣言ではなく単なる代入として扱える
var i int
i, j := 10, 20
var err error
i, err := hoge()
ゼロ値
// 暗黙の初期化
整数型 0
浮動小数点型 0.0
bool false
string ""
配列 各要素がゼロ値の配列
構造体 各フィールドがゼロ値の配列
その他の型 nil
if
// 丸括弧なし ( )
// 波括弧省略不可 { }
// 参考演算子なし
if a > b {
fmt.Println("A")
} else if a == b {
fmt.Println("B")
} else {
fmt.Println("C")
}
for
for i := 0; i < 10; i++ {
fmt.Println(i)
}
n := 0;
for n < 10 {
fmt.Printf("N = %d", n)
n++
}
for {
doSameing()
}
switch
次の case に処理は移らない
次に移す場合は fallthrough を記載
n := 10
swith n {
case 15:
fmt.Println("Fizz")
case 5, 10:
fmt.Println("Buzz")
fallthrough
default:
fmt.Println(n)
}
式も記載可能
n := 10
swith n {
case n%15 == 0:
fmt.Println("FizzBuzz")
case n%5 == 0:
fmt.Println("Buzz")
default:
fmt.Println(n)
}
関数
複数の値を返せる
func hello() {
fmt.Println("hello")
}
// func sum(i int, j int) と同様
func sum(i, j int) {
fmt.Println(i + j)
}
func sum(i, j int) int {
return i + j
}
func swap(i, j int) (int, int) {
return j, i
}
func main() {
x, y = swap(1, 2)
x, _ = swap(3, 4) // 第2戻り値を無視
swap(5, 6) // OK
}
エラーを返す関数
file, err := os.Open("test.txt")
if err != nil {
// エラー処理
}
// 自作のエラー
func dev(i, j int) (int, error) {
if j == 0 {
return 0, error.New("Divied by Zero") // 要 import "errors"
}
return i / j, nil
}
名前付き戻り値
すべて return のみで書ける
func dev(i, j int) (result int, err error) {
if j == 0 {
err = error.New("Divied by Zero")
return // 以下と同様 return 0, err
}
return // 以下と同様 return i / j, nil
}
関数リテラル(無名関数)
main() {
func(i, j int) {
fmt.Println(i + j)
}(2, 4)
}
配列
配列は固定長(可変長配列はスライスを利用)
[6]string という名前の型
[4]string と [2]string は別の型
関数に配列を渡す場合は値渡し
var arr [4]string
arr[0] = "a"
// 初期値設定
arr := [4]string{"a", "b", "c", "d"}
// サイズを暗黙指定
arr := [...]string{"a", "b", "c", "d"}
スライス(可変長配列)
シビアなメモリ管理を必要としないのであればこちらを使用
var s []string
s := []string{"a", "b", "c", "d"}
append()
スライスの末尾に値を追加
var s []string
s = append(s, "a")
s = append(s, "b", "c")
s1 := []string{"a", "b"}
s2 := []string{"c", "d"}
s1 = append(s1, s2...) // s2が展開され追加
range
配列やスライスの内容を先頭から順に取得
string, マップ, チャンネル にも使用可能
arr := []string{"a", "b", "c", "d"}
for i, s := range arr {
fmt.Println(i, s) // 0 a ...
}
値の切り出し
string, 配列, スライス から値を部分的に取得
s := []int{0, 1, 2, 3, 4, 5}
s[2:4] // [2 3]
s[0:len(s)] // [0 1 2 3 4 5]
s[:3] // [3 4 5]
s[:] // [0 1 2 3 4 5]
可変長引数
★ fuc sum(nums []int) (result int) ではダメなのか?
fuc sum(nums ...int) (result int) {
for _, n = range nums {
rezult += n
}
return
}
sun(1, 2, 3, 4, 5)
マップ(連想配列)
// 宣言
var month map[int]string = map[int]string{}
month[1] = "January"
month[2] = "February"
// 宣言と初期化
month := map[int]string{
1: "January",
2: "February",
}
// 取り出し
jan := month[1]
// 存在確認
_, exist := month[1]
if exist {
// データがあった場合
}
// データ削除
delete(month, 1)
// range で取り出し
for key, value := range month {
fmt.Printf("%d %s\n", key, value)
}
ポインタ
参照渡しに使用
書き方はCと同様
ポインタ演算は使えない
func callByRef(i *int) {
*i = 20
}
var i int = 10
callByRef(&i)
defer
指定した処理が関数を抜ける直前に必ず実行される仕組み
ファイルポインタのクローズ等に使用
file, err := os.Open("./error.go")
if err != nil {
// エラー処理
}
// 関数を抜ける前に必ず実行される
defer file.Close()
パニック(try-catch)
パニックで発生したエラーはrecover()という組込み関数で取得
recover()をdeferの中に書くことでパニックで発生したエラーの処理を実施してから関数を抜ける
// 関数を抜ける前に必ず実行される無名関数
defer func() {
err := recover()
if err != nil {
// runtime error: index out of range
log.Fatal(err)
}
}()
panic()
パニックは組込み関数panic()を用いて自分で発生
panic(errors.New("index out of range"))