はじめに
Hello World
すべての Go プログラムは package main の main() 関数から開始されます。'go run' で実行、'go build' でコンパイルします。gofmt が自動的にコードをフォーマットします(タブ、スペース)。import 文でパッケージを取り込みます — fmt はフォーマット済み I/O を扱います。
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
fmt.Printf("Name: %s, Age: %d\n", "Alice", 30)
}
// Run: go run main.go
// Build: go build -o app main.go
// Format: gofmt -w main.goGo モジュール(go.mod)
Go モジュール(go.mod)は Go 1.11 以降の依存関係管理です。'go mod init' でモジュールファイルを作成します。'go get' で依存関係を追加します。'go mod tidy' は未使用のインポートを削除し、不足分を追加します。モジュールパスがパッケージのインポートパスになります。
// Initialize a new module
// $ go mod init github.com/user/project
// go.mod file:
module github.com/user/project
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
golang.org/x/sync v0.3.0
)
// Add dependencies:
// $ go get github.com/gin-gonic/gin
// $ go mod tidy // clean up unused depsパッケージ構造
Go はパッケージでコードを整理します — ディレクトリごとに1パッケージ。大文字で始まる名前(Println、Add)はエクスポート(公開)、小文字はパッケージプライベートです。'internal' ディレクトリは親モジュールへのインポートを制限します。パッケージ名はディレクトリ名と一致させるべきです。
// project structure:
// myproject/
// go.mod
// main.go // package main
// utils/
// helper.go // package utils
// math.go
// internal/
// api/ // private (only importable within parent)
// main.go
package main
import (
"fmt"
"github.com/user/project/utils"
)
func main() {
fmt.Println(utils.Add(1, 2))
}
// Exported names start with uppercase letter
// unexported names start with lowercase letter変数と定数
明示的宣言には 'var name type = value'、短縮宣言には 'name := value'(関数内のみ)を使用します。Go にはゼロ値があります:数値は 0、文字列は ''、ブール値は false、ポインタ/スライス/マッ プは nil。定数(const)はコンパイル時で := は使用できません。
package main
import "fmt"
// Package-level declarations
var version = "1.0.0" // inferred type
const Pi = 3.14159
func main() {
// var with type
var name string = "Alice"
var age int = 30
// Short declaration (only inside functions)
city := "NYC"
// Multiple assignment
a, b, c := 1, 2, 3
// Zero values (default)
var x int // 0
var s string // ""
var ok bool // false
var p *int // nil
fmt.Println(name, age, city, a, b, c, x, s, ok, p)
}基本型と変換
Go は明示的な型変換が必要です — C のような暗黙的変換はありません。rune は int32 のエイリアス(Unicode コードポイントを表す)。byte は uint8 のエイリアス。数値型間の変換は精度を失う可能性があります(float から int は切り捨て)。string(65) はコードポイントを文字に変換します。
// Numeric types
var i int = 42
var i8 int8 = 127
var u uint = 42
var f32 float32 = 3.14
var f64 float64 = 3.141592653589793
// Other types
var b bool = true
var s string = "hello"
var r rune = 'A' // int32 alias for Unicode code point
var by byte = 255 // uint8 alias
// Type conversion (explicit, no implicit conversion)
var n int = 42
var f float64 = float64(n) // int -> float64
var s string = string(65) // 65 -> "A" (rune to string)
var i2 int = int(f) // float64 -> int (truncates)
// Type inference
var x = 42 // int
var y = 3.14 // float64
var z = len("hi") // int文字列とフォーマット
文字列の基礎
Go の文字列は不変のバイトシーケンスです。len() は文字数ではなくバイト数を返します — Unicode の場合は utf8.RuneCountInString() を使用してください。文字列は ==、<、> で辞書式に比較されます。文字列を range するとルーン(Unicode コードポイント)ごとに反復し、マルチバイト文字を正しく処理します。
package main
import (
"fmt"
"strings"
)
func main() {
s := "Hello, World"
// Length (bytes, not runes!)
fmt.Println(len(s)) // 12
// Concatenation
s1 := "Hello" + " " + "World"
s2 := fmt.Sprintf("%s = %d", "age", 30)
// Comparison
fmt.Println("abc" == "abc") // true
fmt.Println("a" < "b") // true (lexicographic)
// Iteration (by rune)
for i, r := range "Go语" {
fmt.Printf("%d: %c\n", i, r)
}
}strings パッケージ
strings パッケージは一般的な文字列操作を提供します。Contains/HasPrefix/HasSuffix で部分文字列をチェックします。Split はデリミタで分割し、Join は結合します。Replace はカウントを取ります(-1 で全て)。TrimSpace は前後の空白を削除します。すべての関数は新しい文字列を返します(文字列は不変です)。
import (
"fmt"
"strings"
)
s := "Hello, World"
// Case
strings.ToUpper(s) // "HELLO, WORLD"
strings.ToLower(s) // "hello, world"
strings.Title("hello world") // "Hello World"
// Search
strings.Contains(s, "World") // true
strings.HasPrefix(s, "Hello") // true
strings.HasSuffix(s, "World") // true
strings.Index(s, "World") // 7 (-1 if not found)
strings.Count(s, "l") // 3
// Split & Join
parts := strings.Split("a,b,c", ",") // ["a", "b", "c"]
joined := strings.Join(parts, "-") // "a-b-c"
// Replace
strings.Replace(s, "l", "L", 1) // "HeLlo, World" (1 occurrence)
strings.ReplaceAll(s, "l", "L") // "HeLLo, WorLd"
strings.TrimSpace(" hi ") // "hi"strconv とフォーマット
strconv は文字列と数値間の変換を行います — 常にエラー戻り値をチェックしてください。fmt.Printf が出力をフォーマットします:%d(int)、%f(float)、%s(string)、%t(bool)、%T(型)、%x(16進数)、%q(引用符付き)。小数点以下2桁には %.2f、ゼロ埋めには %05d を使用します。Sprintf は印刷せずに文字列を返します。
import (
"fmt"
"strconv"
)
// String to number
n, err := strconv.Atoi("42") // string -> int
f, err := strconv.ParseFloat("3.14", 64)
// Number to string
s1 := strconv.Itoa(42) // int -> string
s2 := strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
// Printf formatting
fmt.Printf("Int: %d\n", 42)
fmt.Printf("Float: %.2f\n", 3.14159)
fmt.Printf("String: %s\n", "hi")
fmt.Printf("Bool: %t\n", true)
fmt.Printf("Type: %T\n", 42) // int
fmt.Printf("Hex: %x\n", 255) // ff
fmt.Printf("Pad: %05d\n", 42) // 00042
fmt.Printf("Quote: %q\n", "hi") // "hi"
// Sprintf returns formatted string
result := fmt.Sprintf("Name: %s, Age: %d", "Alice", 30)Raw 文字列と複数行
Raw 文字列(バッククォート)はすべてを文字通りに保持します — エスケープシーケンスなし、複数行にまたがれます。正規表現、SQL、HTML テンプレートに使用します。解釈文字列(ダブルクォート)は \n、\t などを処理します。ループ内の効率的な文字列連結には strings.Builder を使用してください(O(n²) の割り当てを回避)。
// Raw string literal (backticks) - no escape processing
raw := `This is a
multiline string
with \n (literal backslash-n)`
// Interpreted string (double quotes) - processes escapes
interpreted := "Line1\nLine2\tTabbed"
// Raw strings are useful for:
// - Regex patterns
// - HTML/SQL templates
// - File paths on Windows
regex := `^d{4}-d{2}-d{2}$`
// String builder (efficient concatenation)
var sb strings.Builder
for i := 0; i < 1000; i++ {
sb.WriteString("line\n")
}
result := sb.String()Unicode とルーン
Go の文字列は UTF-8 エンコードされたバイトシーケンスです。len() はバイト数、utf8.RuneCountInString() は文字数を返します。文字列の range は UTF-8 を自動的にデコードします。文字列を変更するには、[]rune に変換して変更し、戻します。国際化テキスト処理に不可欠です。
import (
"fmt"
"unicode/utf8"
)
s := "Hello, 世界"
// Byte length vs rune length
fmt.Println(len(s)) // 13 (bytes)
fmt.Println(utf8.RuneCountInString(s)) // 9 (runes/characters)
// Decode runes manually
for i := 0; i < len(s); {
r, size := utf8.DecodeRuneInString(s[i:])
fmt.Printf("%c ", r)
i += size
}
// Range automatically decodes runes
for i, r := range s {
fmt.Printf("%d:%c ", i, r)
}
// Rune slice (mutable)
runes := []rune("Hello")
runes[0] = 'J'
s2 := string(runes) // "Jello"制御フロー
If / Else
Go の if は条件に括弧不要ですが、ブレースは必須です(単文本体でも)。初期化文(if x := f(); x > 0)は if/else ブロックにスコープされます — エラーチェックに一般的です。このパターンは変数スコープを狭く保ちます。
// Basic if/else
score := 85
if score >= 90 {
fmt.Println("A")
} else if score >= 80 {
fmt.Println("B")
} else {
fmt.Println("C")
}
// If with initialization statement
if n := computeValue(); n > 100 {
fmt.Println("big:", n)
} else {
fmt.Println("small:", n)
}
// n is not accessible here (scoped to if)
// No parentheses needed, but braces are requiredFor ループ
Go にはループキーワードが1つだけです:'for'。C スタイル、while スタイル(for cond)、無限(for)、反復(for range)を処理します。range はスライス、マップ、文字列、チャネルで動作します。インデックスや値をスキップするには _ を使用します。マップの反復順序は設計上ランダムです。