Go言語入門:よくある質問 -デザイン Vol.3-

スポンサーリンク
Go言語入門:よくある質問 -デザイン Vol.3- ノウハウ
Go言語入門:よくある質問 -デザイン Vol.3-
この記事は約5分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語のよくある質問 について解説しています。

スポンサーリンク

背景

Go言語を学んでいると「なんでこんな仕様になっているんだろう?」「他の言語と違うのはなぜ?」といった疑問が湧いてきませんか。Go言語の公式サイトにあるFAQページには、そんな疑問に対する開発チームからの丁寧な回答がたくさん載っているんです。ただ、英語で書かれているため読むのに少しハードルがあるのも事実で、今回はこのFAQを日本語に翻訳して、Go言語への理解を深めていけたらと思い、これを読んだ時の内容を備忘として残しました。

デザイン

なぜGoには機能Xがないのですか?

すべての言語には新しい機能が含まれ、誰かのお気に入りの機能が省略されています。Goは、プログラミングの快適性、コンパイル速度、概念の直交性、そして並行処理やガベージコレクションなどの機能をサポートする必要性を考慮して設計されました。あなたのお気に入りの機能が欠けているのは、それが適合しないから、コンパイル速度や設計の明確性に影響するから、または基本的なシステムモデルを過度に困難にするからかもしれません。

GoにX機能が欠けていることが気になる場合は、私たちを許してください。そして、Goが実際に持っている機能を調べてください。Xの欠如を興味深い方法で補っていることがわかるかもしれません。

解説

この節は、Go言語の設計哲学の核心を表現している重要な部分です。なぜ特定の機能が意図的に省略されたのか、その背景にある考え方を説明しています。

Go言語の設計原則

プログラミングの快適性(Felicity of Programming)

  • シンプルさ: 覚えるべき概念の数を最小限に
  • 予測可能性: コードの動作が直感的
  • 読みやすさ: 他人のコードが理解しやすい

コンパイル速度の重視 Go言語が高速コンパイルを実現する理由:

  • 依存関係の明確化: 循環依存の禁止
  • ヘッダーファイルの廃止: 重複解析の回避
  • シンプルな文法: パースが高速

概念の直交性(Orthogonality)

  • 独立した機能: 一つの機能が他に影響しない
  • 組み合わせ可能: 機能を予測可能な方法で組み合わせられる
  • 最小限の例外: 特殊ケースを避ける

意図的に省略された機能の例

ジェネリクス(Go 1.18で追加される前)

// 省略されていた理由
// - コンパイル速度への影響
// - 言語の複雑化
// - 代替手段の存在(interface{}、コード生成)

// Go 1.18で慎重に導入
func Min[T comparable](a, b T) T {
    if a < b {
        return a
    }
    return b
}

例外処理

// Goにはtry-catchがない
// 代わりにエラー値を使用
result, err := someFunction()
if err != nil {
    return err
}

クラス継承

// 継承の代わりに組み込み(embedding)を使用
type Person struct {
    Name string
}

type Employee struct {
    Person  // 組み込み
    JobTitle string
}

省略の理由と代替手段

機能が「適合しない」場合

  • Go の哲学に反する: 複雑さよりもシンプルさを重視
  • 他の機能と衝突: 既存の設計と整合性が取れない

コンパイル速度・設計明確性への影響

// 避けられた複雑さの例

// C++スタイルの複雑な継承階層
// class A : public B, virtual public C, private D { ... }

// Goのシンプルなアプローチ
type A struct {
    B
    c C
    d d
}

システムモデルの困難化

  • ガベージコレクションとの兼ね合い: 手動メモリ管理の排除
  • 並行処理との相性: データ競合を避ける設計

「興味深い方法での補完」の例

ジェネリクスの代わりに

// インターフェースによる抽象化
type Writer interface {
    Write([]byte) (int, error)
}

// 空のインターフェースによる汎用性
func Print(v interface{}) {
    fmt.Println(v)
}

例外処理の代わりに

// 明示的なエラーハンドリング
if err := doSomething(); err != nil {
    log.Printf("操作に失敗: %v", err)
    return
}

継承の代わりに

// インターフェースによる多態性
type Shape interface {
    Area() float64
}

// 組み込みによるコード再利用
type Circle struct {
    *Point  // 組み込み
    Radius float64
}

このアプローチの利点

学習コストの削減

  • 覚える機能が少ない: 習得が容易
  • 一貫した書き方: チーム開発に適している

保守性の向上

  • 予測可能なコード: バグが少ない
  • リファクタリングが容易: 影響範囲が明確

長期的な安定性

  • 言語仕様の安定: 頻繁な変更がない
  • 下位互換性: 既存コードが動き続ける

建設的な姿勢 この節の最後の「私たちを許してください」という表現は、Go言語開発チームの謙虚さと、ユーザーに対する建設的な姿勢を示しています。不満を持つのではなく、既存の機能でどのように問題を解決できるかを探ることを促しています。

この哲学により、Go言語は「少ない機能で多くのことを実現する」言語として、多くの開発者に愛され続けています。

おわりに 

本日は、Go言語のよくある質問について解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました