プログラミング · Go
Go構文のタイピング練習
Go の構文を、初級・中級・上級の3つのリストで打って覚えます。package と import、:= による宣言、if・for・switch、関数と複数の戻り値、構造体とメソッド、エラー処理まで、実際に書く形のまま練習できます。
3リスト・109語
無料・ログインなしで練習できます。押すとこのパックをフォローし、すぐに練習が始まります。
収録している言葉
Go構文(初級)
| 打つ言葉 | 意味・補足 |
|---|---|
| package main | package:所属パッケージを宣言(mainパッケージのmain関数が実行開始点) |
| import "fmt" | import:パッケージを読み込む(未使用importはコンパイルエラー) |
| // コメント | //:1行コメント |
| var age int | var 名前 型:ゼロ値で宣言(intのゼロ値は0) |
| var age int = 20 | var 名前 型 = 値:型と初期値を指定 |
| var age = 20 | var 名前 = 値:型推論で宣言 |
| age := 20 | 名前 := 値:短い変数宣言(関数内のみ。同じブロックでは左辺に少なくとも1つ新しい変数が必要) |
| age = 21 | 名前 = 値:既存変数への代入(ageは宣言済みであること) |
| const Max = 100 | const:定数 |
| _ = age | _:値を捨てる(ブランク識別子) |
| var enabled bool | bool:真偽値(ゼロ値false) |
| name := "Pomo" | string:文字列(ゼロ値は空文字。文字列は不変) |
| var b byte = 'A' | byte:uint8の別名 |
| var r rune = 'あ' | rune:int32の別名(Unicodeコードポイントなどに使用) |
| same := a == b | == / !=:等値・不等値比較(比較できない型もある) |
| count += 2 | += -= *= /=:複合代入 |
| count++ | ++ / --:1増減(式ではなく文。x := count++は不可) |
| n := 1 << 3 | << / >>:ビットシフト |
| for { break } | for:無限ループ |
| if done { break } | break:ループを抜ける(break可能な構文内で使用) |
| return result | return:関数から戻る |
| first := s[0] | s[i]:要素へアクセス(範囲外はpanic) |
| part := s[1:3] | s[low:high]:部分範囲(low以上high未満。元の配列を共有する場合がある) |
| n := len(s) | len:長さ(文字列ではバイト数) |
| name := u.Name | 値.フィールド:フィールド参照 |
| p := &u | &値:アドレス取得 |
| var p *User | *型:ポインタ型(ゼロ値はnil) |
| copyOfUser := *p | *ポインタ:参照先の値(nilの参照外しはpanic) |
| u.Birthday() | 値.メソッド():メソッド呼び出し(必要な条件下でアドレス取得等が自動的に補われる) |
| defer f.Close() | defer:関数終了時の処理を登録(ファイルを正常に開いた後に登録。後入れ先出し。引数は登録時に評価) |
| go work() | go f():goroutineで実行(mainの終了時に他のgoroutineを自動で待たない) |
| ch <- 10 | ch <- value:channelへ送信(閉じたchannelへの送信はpanic) |
| value := <-ch | channelから受信 |
| close(ch) | channelを閉じる(通常は送信側が所有権を持って閉じる。二重closeはpanic) |
| _ = value | 未使用ローカル変数・import:コンパイル時の検査(未使用のローカル変数やimportは通常エラー) |
| var p *User = nil | nil:参照を持たない値(ポインタ・スライス・map・channel・関数・インターフェース等で使用) |
| gofmt -w main.go | gofmt:標準書式で整形(Go構文ではなくターミナルのコマンド。ファイルを上書き) |
Go構文(中級)
| 打つ言葉 | 意味・補足 |
|---|---|
| import ( "fmt"; "errors" ) | import (...):複数パッケージを読み込む |
| /* 複数行の コメント */ | /* ... */:複数行コメント |
| if true { fmt.Println("OK") } | { ... }:ブロック(通常は行末のセミコロンを省略。開始の{はifやfuncなどと同じ行) |
| name, age := "Pomo", 20 | 複数の短い変数宣言:複数変数を宣言 |
| f := float64(age) | 型(値):明示的な型変換(数値型間でも通常は暗黙に変換しない) |
| s := strconv.Itoa(age) | strconv.Itoa:整数の文字列表現を得る(strconvのimportが必要。string(age)は整数の10進文字列化ではない) |
| var count int64 = 100 | int / int64:符号付き整数(ゼロ値0。intの幅は実装に依存) |
| var count uint64 = 100 | uint / uint64:符号なし整数(ゼロ値0) |
| var rate float64 = 0.5 | float32 / float64:浮動小数点数(ゼロ値0) |
| remainder := 10 % 3 | + - * / %:加減乗除・余り(%は整数。整数同士の除算は小数部を切り捨て) |
| adult := age >= 20 | < <= > >=:大小比較(順序比較可能な型で使用) |
| ok := enabled && !blocked | && || !:論理演算 |
| masked := flags & 3 | & | ^ &^:ビット演算(整数型で使用。&は文脈によってアドレス取得) |
| for count < 5 { count++ } | for 条件:条件ループ |
| if skip { continue } | continue:次の繰り返しへ(ループ内で使用) |
| total := sum(values...) | 引数...:スライスを可変長引数へ展開(valuesは[]int) |
| a := [3]int{ 1, 2, 3 } | [長さ]型{...}:固定長配列(長さは型の一部) |
| s := []int{ 1, 2, 3 } | []型{...}:スライス |
| s := make([]int, 3) | make([]型, 長さ):指定長のスライス(要素はゼロ値) |
| s := make([]int, 0, 10) | make([]型, 長さ, 容量):長さ・容量を指定 |
| s = append(s, 4) | append:スライスに追加(返り値を受け取る) |
| capacity := cap(s) | cap:スライスの容量 |
| m := make(map[string]int) | make(map[キー型]値型):空のmapを作成 |
| m["apple"] = 120 | m[key] = value:追加・更新(nilのmapへの書き込みはpanic) |
| v, ok := m["apple"] | v, ok := m[key]:値と存在有無を取得(存在しない場合vは値型のゼロ値) |
| delete(m, "apple") | delete:キーを削除(存在しないキーでもエラーにならない) |
| var v any = "hello" | any:任意の型を保持(interface{}の別名) |
| s := v.(string) | v.(型):型アサーション(型が異なるとpanic) |
| s, ok := v.(string) | v, ok := x.(型):安全な型アサーション(型が異なる場合ok=false) |
| panic("想定外の状態") | panic:スタックを巻き戻して通常処理を中断(通常の失敗はerrorで扱う) |
| n, ok := First([]int{ 10, 20 }) | 型引数の推論:型引数を省略(推論できる場合のみ) |
| ch := make(chan int) | make(chan 型):バッファなしchannel(送受信に相手が必要) |
| ch := make(chan int, 10) | make(chan 型, 容量):バッファ付きchannel(満杯の送信・空の受信は待つ) |
| value, ok := <-ch | 受信値と状態(閉じてバッファが空ならok=false) |
| func Exported() { } | 大文字開始の名前:パッケージ外へ公開(外側の型・パッケージ等のアクセス条件も関係) |
| n := len("あ") | len(文字列):文字列のバイト数(UTF-8で3。Unicodeコードポイント数ならutf8.RuneCountInString等) |
Go構文(上級)
| 打つ言葉 | 意味・補足 |
|---|---|
| func main() { fmt.Println("Hello, Go!") } | func main():実行開始の関数(fmtのimportが必要) |
| var label string; if age >= 20 { label = "成人" } else { label = "未成年" } | 三項演算子なし:条件による値の選択(条件 ? A : Bは使わない) |
| if age >= 20 { fmt.Println("成人") } else { fmt.Println("未成年") } | if / else:条件で分岐(条件を丸括弧で囲む必要はない。elseは直前の}と同じ行) |
| if n := len(name); n > 0 { fmt.Println(n) } | if 初期化; 条件:初期化付きの条件分岐(nはこのifと続くelse内で有効) |
| switch role { case "admin": fmt.Println("管理者"); case "member", "guest": fmt.Println("一般利用者"); default: fmt.Println("不明") } | switch / case / default:値で分岐(通常はcase末尾にbreak不要) |
| for i := 0; i < 5; i++ { fmt.Println(i) } | for 初期化; 条件; 更新:回数指定ループ(while構文はない) |
| for i, v := range items { fmt.Println(i, v) } | for i, v := range items:添字と値を取得(itemsは配列・スライス等) |
| for _, v := range items { fmt.Println(v) } | for _, v := range items:値だけを使用 |
| for k, v := range m { fmt.Println(k, v) } | for k, v := range m:mapのキーと値を取得(mapの列挙順は保証されない) |
| for i, r := range "あいう" { fmt.Println(i, r) } | 文字列のrange:バイト位置とruneを取得(添字は文字番号ではなくバイト位置) |
| func greet(name string) { fmt.Println(name) } | func 名前(引数):戻り値なしの関数 |
| func add(a, b int) int { return a + b } | func 名前(引数) 型:戻り値ありの関数 |
| func pair() (int, string) { return 1, "one" } | 複数の戻り値:複数の値を返す |
| func sum(nums ...int) int { total := 0; for _, n := range nums { total += n }; return total } | ...型:可変長引数(可変長引数は最後に置く) |
| f := func(x int) int { return x * 2 } | 無名関数:関数を値として保持 |
| func() { fmt.Println("実行") }() | func() { ... }():無名関数を即時実行 |
| m := map[string]int{ "apple": 100 } | map[キー型]値型{...}:mapを作成(キー型はcomparable) |
| type User struct { Name string; Age int } | type 名前 struct:構造体を定義 |
| u := User{ Name: "Pomo", Age: 20 } | 型{フィールド: 値}:構造体の値を作る |
| func (u User) Greet() string { return "こんにちは、" + u.Name } | 値レシーバー:値を受け取るメソッド |
| func (u *User) Birthday() { u.Age++ } | ポインタレシーバー:参照先を変更するメソッド |
| type Greeter interface { Greet() string } | type 名前 interface:メソッドの集合を定義(必要なメソッドを持つ型が暗黙に満たす) |
| var g Greeter = User{ Name: "Pomo" } | インターフェースへ代入:実装を抽象型で扱う(UserにGreetメソッドが必要) |
| switch x := v.(type) { case string: fmt.Println(x); case int: fmt.Println(x) } | switch x := v.(type):型による分岐 |
| func divide(a, b int) (int, error) { if b == 0 { return 0, errors.New("ゼロでは割れません") }; return a / b, nil } | errorの戻り値:通常の失敗を値で返す(errorsのimportが必要) |
| result, err := divide(10, 2); if err != nil { fmt.Println(err); return }; fmt.Println(result) | if err != nil:エラーを確認(例はmain関数内) |
| err := errors.New("失敗しました") | errors.New:エラーを生成(errorsのimportが必要) |
| return fmt.Errorf("読み込み失敗: %w", err) | fmt.Errorf / %w:元のエラーをラップ(errorを返す関数内。fmtのimportが必要) |
| defer func() { if r := recover(); r != nil { fmt.Println(r) } }() | recover:同じgoroutineのpanicを回収(deferされた関数内で直接呼ぶ) |
| func First[T any](items []T) (T, bool) { if len(items) == 0 { var zero T; return zero, false }; return items[0], true } | [T any]:任意の型の型パラメーター |
| func Equal[T comparable](a, b T) bool { return a == b } | [T comparable]:比較可能な型に制限 |
| n, ok := First[int]([]int{ 10, 20 }) | 関数[型](引数):型引数を明示 |
| for v := range ch { fmt.Println(v) } | for v := range ch:終了まで受信(閉じられて値が尽きると終了) |
| select { case v: = <-ch: fmt.Println(v); case <-done: return } | select:複数の通信を待つ(この例は関数内。chとdoneは初期化済み) |
| ch := make(chan string); go func() { ch <- "完了" }(); message := <-ch; fmt.Println(message) | goroutineとchannelの組合せ:送信・受信を同期(fmtのimportが必要) |
| package main; import "fmt"; func main() { fmt.Println("Hello, Go!") } | コード例の前提:コード断片の利用範囲(多くの例は関数内の断片。宣言・import・変数等を補って利用) |