Go
#12
TIOBE#7
PYPL#12
GitHub#20
RedMonk#12
IEEESpectrum#8
JetBrains#11
プログラミング言語
Go
概要
Goは、Googleが開発したシンプルで高性能なプログラミング言語です。
詳細
Goは2009年にGoogleのRobert Griesemer、Rob Pike、Ken Thompsonによって開発されたオープンソースのプログラミング言語です。シンプルで読みやすい構文、高速なコンパイル、優れた並行処理機能を特徴としています。ガベージコレクションを持ちながらも高性能を実現し、大規模なシステム開発に適しています。マイクロサービス、クラウドアプリケーション、DevOpsツールの開発で特に人気があり、Docker、Kubernetes、Prometheusなどの重要なツールがGoで書かれています。
書き方の例
Hello World
package main
import "fmt"
// 基本的な出力
func main() {
fmt.Println("Hello, World!")
// 変数を使った出力
message := "こんにちは、Go!"
fmt.Println(message)
// フォーマット文字列を使った出力
name := "太郎"
age := 25
fmt.Printf("私の名前は%sで、%d歳です。\n", name, age)
}
変数と型
package main
import "fmt"
func main() {
// 基本的な型
var name string = "太郎"
var age int = 25
var height float64 = 175.5
var isActive bool = true
// 短縮形での変数宣言
city := "東京"
temperature := 22.5
// 複数変数の同時宣言
var (
firstName string = "田中"
lastName string = "太郎"
score int = 85
)
// 定数
const Pi = 3.14159
const MaxUsers = 100
fmt.Printf("名前: %s, 年齢: %d, 身長: %.1fcm\n", name, age, height)
fmt.Printf("都市: %s, 気温: %.1f度\n", city, temperature)
fmt.Printf("フルネーム: %s %s, スコア: %d\n", firstName, lastName, score)
fmt.Printf("円周率: %g, 最大ユーザー数: %d\n", Pi, MaxUsers)
}
配列、スライス、マップ
package main
import "fmt"
func main() {
// 配列(固定長)
var numbers [5]int = [5]int{1, 2, 3, 4, 5}
fruits := [3]string{"りんご", "バナナ", "オレンジ"}
// スライス(可変長)
colors := []string{"赤", "青", "緑"}
colors = append(colors, "黄色") // 要素の追加
// make関数でスライス作成
scores := make([]int, 3, 5) // 長さ3, 容量5
scores[0] = 85
scores[1] = 92
scores[2] = 78
// マップ(辞書)
person := map[string]interface{}{
"name": "田中太郎",
"age": 30,
"city": "東京",
}
// make関数でマップ作成
grades := make(map[string]int)
grades["数学"] = 85
grades["英語"] = 92
grades["国語"] = 78
fmt.Printf("配列: %v\n", numbers)
fmt.Printf("果物: %v\n", fruits)
fmt.Printf("色: %v\n", colors)
fmt.Printf("スコア: %v\n", scores)
fmt.Printf("人: %v\n", person)
fmt.Printf("成績: %v\n", grades)
}
関数
package main
import "fmt"
// 基本的な関数
func add(a, b int) int {
return a + b
}
// 複数の戻り値
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("ゼロで除算はできません")
}
return a / b, nil
}
// 名前付き戻り値
func rectangle(width, height float64) (area, perimeter float64) {
area = width * height
perimeter = 2 * (width + height)
return // 名前付き戻り値は自動的に返される
}
// 可変長引数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// 高階関数(関数を引数に取る)
func applyOperation(a, b int, operation func(int, int) int) int {
return operation(a, b)
}
func main() {
// 関数の呼び出し
result := add(10, 5)
fmt.Printf("10 + 5 = %d\n", result)
// 複数戻り値の処理
quotient, err := divide(10, 3)
if err != nil {
fmt.Printf("エラー: %v\n", err)
} else {
fmt.Printf("10 ÷ 3 = %.2f\n", quotient)
}
// 名前付き戻り値
area, perimeter := rectangle(5, 3)
fmt.Printf("長方形 - 面積: %.1f, 周囲: %.1f\n", area, perimeter)
// 可変長引数
total := sum(1, 2, 3, 4, 5)
fmt.Printf("合計: %d\n", total)
// 高階関数
multiply := func(x, y int) int { return x * y }
product := applyOperation(4, 6, multiply)
fmt.Printf("4 × 6 = %d\n", product)
}
構造体とメソッド
package main
import "fmt"
// 構造体の定義
type Person struct {
Name string
Age int
City string
}
// メソッドの定義(レシーバー付き関数)
func (p Person) GetInfo() string {
return fmt.Sprintf("%s(%d歳、%s在住)", p.Name, p.Age, p.City)
}
// ポインタレシーバー(構造体を変更する場合)
func (p *Person) SetAge(newAge int) {
p.Age = newAge
}
// 埋め込み(継承のような機能)
type Employee struct {
Person // Personを埋め込み
JobTitle string
Salary int
}
func (e Employee) GetJobInfo() string {
return fmt.Sprintf("%s - 職種: %s, 給与: %d円", e.GetInfo(), e.JobTitle, e.Salary)
}
func main() {
// 構造体のインスタンス作成
person1 := Person{
Name: "田中太郎",
Age: 25,
City: "東京",
}
// フィールドへのアクセス
fmt.Println("名前:", person1.Name)
fmt.Println("年齢:", person1.Age)
// メソッドの呼び出し
fmt.Println(person1.GetInfo())
// ポインタレシーバーメソッドの呼び出し
person1.SetAge(26)
fmt.Println("更新後:", person1.GetInfo())
// 埋め込み構造体
employee := Employee{
Person: Person{
Name: "山田花子",
Age: 30,
City: "大阪",
},
JobTitle: "エンジニア",
Salary: 5000000,
}
fmt.Println(employee.GetJobInfo())
}
インターフェース
package main
import "fmt"
// インターフェースの定義
type Shape interface {
Area() float64
Perimeter() float64
}
// 長方形の構造体
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// 円の構造体
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
// インターフェースを受け取る関数
func printShapeInfo(s Shape) {
fmt.Printf("面積: %.2f, 周囲: %.2f\n", s.Area(), s.Perimeter())
}
func main() {
rectangle := Rectangle{Width: 5, Height: 3}
circle := Circle{Radius: 2}
// 同じインターフェースとして扱う
printShapeInfo(rectangle)
printShapeInfo(circle)
// インターフェーススライス
shapes := []Shape{rectangle, circle}
for i, shape := range shapes {
fmt.Printf("図形%d: ", i+1)
printShapeInfo(shape)
}
}
Goroutine(並行処理)
package main
import (
"fmt"
"sync"
"time"
)
// 基本的なgoroutine
func sayHello(name string) {
for i := 0; i < 3; i++ {
fmt.Printf("Hello %s! (%d)\n", name, i+1)
time.Sleep(100 * time.Millisecond)
}
}
// WaitGroupを使った同期
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 関数終了時にDone()を呼ぶ
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
// 基本的なgoroutine
go sayHello("Alice")
go sayHello("Bob")
// メインgoroutineで少し待機
time.Sleep(400 * time.Millisecond)
fmt.Println("---")
// WaitGroupを使った同期処理
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // カウンターを増やす
go worker(i, &wg)
}
wg.Wait() // すべてのgoroutineが完了するまで待機
fmt.Println("All workers completed")
}
チャネル(並行処理での通信)
package main
import (
"fmt"
"time"
)
// 基本的なチャネル
func sender(ch chan string) {
messages := []string{"Hello", "Go", "Channels"}
for _, msg := range messages {
ch <- msg // チャネルに送信
time.Sleep(100 * time.Millisecond)
}
close(ch) // チャネルを閉じる
}
// バッファ付きチャネル
func bufferedChannelExample() {
ch := make(chan int, 3) // バッファサイズ3
// 非同期でデータを送信
go func() {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Printf("Sent: %d\n", i)
}
close(ch)
}()
// データを受信
for value := range ch {
fmt.Printf("Received: %d\n", value)
time.Sleep(200 * time.Millisecond)
}
}
// selectを使った複数チャネルの制御
func selectExample() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
ch1 <- "Channel 1"
}()
go func() {
time.Sleep(200 * time.Millisecond)
ch2 <- "Channel 2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("From ch1:", msg1)
case msg2 := <-ch2:
fmt.Println("From ch2:", msg2)
case <-time.After(300 * time.Millisecond):
fmt.Println("Timeout")
}
}
}
func main() {
fmt.Println("=== 基本的なチャネル ===")
ch := make(chan string)
go sender(ch)
for message := range ch {
fmt.Println("Received:", message)
}
fmt.Println("\n=== バッファ付きチャネル ===")
bufferedChannelExample()
fmt.Println("\n=== Select文 ===")
selectExample()
}
エラーハンドリング
package main
import (
"errors"
"fmt"
"os"
)
// カスタムエラー型
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("Validation error in %s: %s", e.Field, e.Message)
}
// エラーを返す関数
func validateAge(age int) error {
if age < 0 {
return ValidationError{
Field: "age",
Message: "年齢は0以上である必要があります",
}
}
if age > 150 {
return ValidationError{
Field: "age",
Message: "年齢は150以下である必要があります",
}
}
return nil
}
// ファイル操作でのエラーハンドリング
func readFile(filename string) (string, error) {
content, err := os.ReadFile(filename)
if err != nil {
return "", fmt.Errorf("ファイル読み込みエラー: %w", err)
}
return string(content), nil
}
// panicとrecover
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Panic回復: %v\n", r)
}
}()
fmt.Println("危険な処理を実行中...")
panic("何かがうまくいかなかった!")
fmt.Println("この行は実行されません")
}
func main() {
// エラーハンドリングの例
ages := []int{25, -5, 200, 30}
for _, age := range ages {
if err := validateAge(age); err != nil {
fmt.Printf("エラー - 年齢 %d: %v\n", age, err)
// 型アサーションでカスタムエラーかチェック
if ve, ok := err.(ValidationError); ok {
fmt.Printf(" フィールド: %s\n", ve.Field)
}
} else {
fmt.Printf("年齢 %d は有効です\n", age)
}
}
// ファイル読み込みエラーの例
_, err := readFile("nonexistent.txt")
if err != nil {
fmt.Printf("ファイルエラー: %v\n", err)
}
// panic/recoverの例
fmt.Println("\n=== Panic/Recover ===")
riskyFunction()
fmt.Println("メイン処理は継続されます")
}
バージョン
バージョン | リリース日 | 主な新機能 |
---|---|---|
Go 1.23 | 2024-08 | Range-over-func, Timer reset behavior |
Go 1.22 | 2024-02 | For-range over integers, Math/rand v2 |
Go 1.21 | 2023-08 | Built-in functions min/max/clear, WASM |
Go 1.20 | 2023-02 | Comparable types, Context improvements |
Go 1.19 | 2022-08 | Generics improvements, Doc comments |
Go 1.18 | 2022-03 | Generics, Fuzzing, Workspaces |
Go 1.17 | 2021-08 | Module graph pruning, Call stack traces |
参考ページ
公式ドキュメント
- Go公式サイト - 公式サイト
- Go Documentation - 公式ドキュメント
- A Tour of Go - インタラクティブなGoチュートリアル
学習リソース
- Go by Example - 実例によるGo学習
- Effective Go - 効果的なGoの書き方
- Go Wiki - Goに関する詳細情報
開発ツール
- Go Packages - Goパッケージドキュメント
- Go Playground - ブラウザ上でGoを試せる環境
- Awesome Go - Goライブラリ・ツール集