Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11520] ファイルの概要

このコミットは、Go言語の標準ライブラリであるnetパッケージ内のDNSConfigError型を、src/pkg/net/dnsconfig.goからsrc/pkg/net/net.goへ移動する変更を含んでいます。これにより、DNSConfigErrorがWindows環境でも利用可能となり、netパッケージのAPIシグネチャのプラットフォーム間の差異が解消されます。

コミット

net: move DNSConfigError to a portable file

The type being unavailable on Windows was the only API
signature difference in the net package.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5608043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/549ca930a068ebdf05133656ecde085368e18faa

元コミット内容

commit 549ca930a068ebdf05133656ecde085368e18faa
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Tue Jan 31 13:01:34 2012 -0800

    net: move DNSConfigError to a portable file

    The type being unavailable on Windows was the only API
    signature difference in the net package.

    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5608043
---
 src/pkg/net/dnsconfig.go | 13 -------------\n src/pkg/net/net.go       | 12 ++++++++++++\n 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/pkg/net/dnsconfig.go b/src/pkg/net/dnsconfig.go
index c0ab80288d..bb46cc9007 100644
--- a/src/pkg/net/dnsconfig.go
+++ b/src/pkg/net/dnsconfig.go
@@ -17,19 +17,6 @@ type dnsConfig struct {
 	rotate   bool     // round robin among servers
 }

-var dnsconfigError error
-
-type DNSConfigError struct {
-	Err error
-}
-
-func (e *DNSConfigError) Error() string {
-	return "error reading DNS config: " + e.Err.Error()
-}
-
-func (e *DNSConfigError) Timeout() bool   { return false }
-func (e *DNSConfigError) Temporary() bool { return false }
-
 // See resolv.conf(5) on a Linux machine.
 // TODO(rsc): Supposed to call uname() and chop the beginning
 // of the host name to get the default search domain.
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 84cb4fcc73..79d36a2a81 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -201,3 +201,15 @@ type UnknownNetworkError string
 func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
 func (e UnknownNetworkError) Temporary() bool { return false }
 func (e UnknownNetworkError) Timeout() bool   { return false }
+
+// DNSConfigError represents an error reading the machine's DNS configuration.
+type DNSConfigError struct {
+	Err error
+}
+
+func (e *DNSConfigError) Error() string {
+	return "error reading DNS config: " + e.Err.Error()
+}
+
+func (e *DNSConfigError) Timeout() bool   { return false }
+func (e *DNSConfigError) Temporary() bool { return false }

変更の背景

このコミットの主な背景は、Go言語のnetパッケージにおけるAPIシグネチャのプラットフォーム間の統一性を確保することにありました。以前は、DNSConfigError型がWindows環境では利用できず、これがnetパッケージのAPIにおいて唯一のプラットフォーム間の差異となっていました。

Go言語はクロスプラットフォーム開発を強く意識しており、可能な限りOSに依存しない一貫したAPIを提供することを目指しています。DNSConfigErrorが特定のOS(この場合はWindows)でのみ利用できないという状況は、この設計思想に反していました。開発者が異なるOS上で同じGoのコードを記述する際に、APIの挙動が異なることは混乱を招き、コードの移植性を損なう可能性があります。

この問題を解決するため、DNSConfigErrorをプラットフォームに依存しないファイルに移動することで、すべてのサポート対象OSでこの型が利用可能になり、netパッケージのAPIが完全に統一されることになりました。これにより、Goのネットワーク関連コードのポータビリティと予測可能性が向上します。

前提知識の解説

Go言語のnetパッケージ

Go言語の標準ライブラリであるnetパッケージは、ネットワークI/Oの基本的な機能を提供します。TCP/IP、UDP、Unixドメインソケットなどのネットワークプロトコルを扱うためのインターフェースや、DNSルックアップ、IPアドレスの操作などの機能が含まれています。このパッケージは、Goアプリケーションがネットワーク通信を行う上で不可欠な基盤となります。

DNS (Domain Name System)

DNSは、インターネット上のコンピュータやサービスを識別するための分散型命名システムです。人間が覚えやすいドメイン名(例: example.com)を、コンピュータが理解できるIPアドレス(例: 192.0.2.1)に変換する役割を担っています。Goのnetパッケージは、このDNSルックアップ機能を提供し、ホスト名からIPアドレスを解決したり、その逆を行ったりすることができます。

DNS設定ファイル

Unix系OS(Linux, macOSなど)では、DNSリゾルバの設定は通常/etc/resolv.confファイルに記述されています。このファイルには、DNSサーバーのIPアドレスや検索ドメインなどが含まれます。Goのnetパッケージは、システムがDNSルックアップを行う際に、この設定ファイルを読み取って利用します。

エラーハンドリングとerrorインターフェース

Go言語では、エラーは組み込みのerrorインターフェースによって表現されます。このインターフェースは、Error() stringという単一のメソッドを持ち、エラーメッセージを文字列として返します。Goの慣習として、関数は通常、最後の戻り値としてerror型を返します。

さらに、Go 1.13以降では、エラーのラップ(fmt.Errorf%w動詞)やアンラップ(errors.Unwrap)、特定のエラー型との比較(errors.Is)、特定のエラー型への変換(errors.As)といった機能が導入され、より柔軟なエラーハンドリングが可能になっています。

net.Errorインターフェース

netパッケージには、ネットワーク関連のエラーに特化したnet.Errorインターフェースが定義されています。このインターフェースは、標準のerrorインターフェースに加えて、以下の2つのメソッドを追加します。

  • Timeout() bool: エラーがタイムアウトによるものかどうかを示す。
  • Temporary() bool: エラーが一時的なものであり、再試行によって解決する可能性があるかどうかを示す。

DNSConfigErrorもこのnet.Errorインターフェースを実装しており、DNS設定の読み取りエラーが一時的なものではないこと(Temporary() false)や、タイムアウトによるものではないこと(Timeout() false)を示しています。

プラットフォーム依存のコード

Go言語では、ビルドタグ(build tags)やファイル名規則(例: _windows.go, _linux.go)を使用して、特定のOSやアーキテクチャに依存するコードを記述することができます。これにより、異なるプラットフォームで異なる実装を提供しつつ、共通のAPIを維持することが可能です。しかし、このコミットの背景にあるように、APIシグネチャ自体がプラットフォーム間で異なると、共通のコードを書くことが難しくなります。

技術的詳細

このコミットの技術的な核心は、DNSConfigErrorというカスタムエラー型を、プラットフォーム固有のDNS設定を扱うファイル(src/pkg/net/dnsconfig.go)から、より汎用的なネットワーク関連の型が定義されているファイル(src/pkg/net/net.go)へ移動した点にあります。

src/pkg/net/dnsconfig.goからの削除

元のsrc/pkg/net/dnsconfig.goファイルには、dnsConfig構造体(DNS設定を保持)と、DNSConfigError型が定義されていました。dnsconfig.goは、主にUnix系システムにおける/etc/resolv.confのようなDNS設定ファイルの読み込みに関連するロジックを含んでいました。Windowsシステムでは、DNS設定の取得方法が異なるため、このファイル自体がビルドに含まれないか、あるいはその一部の機能が利用できない可能性がありました。

DNSConfigError型がこのファイルに定義されていたため、Windows環境ではこの型がコンパイル時に存在しない、あるいは参照できないという問題が発生していました。これは、netパッケージの他の部分がDNSConfigErrorを参照しようとした際に、Windowsビルドでエラーとなるか、あるいはAPIのシグネチャがWindowsとUnix系OSで異なってしまう原因となっていました。

削除されたコードは以下の通りです。

var dnsconfigError error // この変数はDNSConfigError型とは直接関係ないが、同じファイルにあった
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

src/pkg/net/net.goへの追加

src/pkg/net/net.goは、netパッケージの主要な型やインターフェース、汎用的なエラー型(例: UnknownNetworkError)などが定義されているファイルです。このファイルは、Goがサポートするすべてのプラットフォームで共通してビルドされることが期待されます。

DNSConfigError型をこのnet.goファイルに移動することで、このエラー型がどのプラットフォームでも常に利用可能になります。これにより、netパッケージ内の他の関数やメソッドがDNSConfigErrorを戻り値として返したり、引数として受け取ったりする際に、プラットフォーム間の差異を気にすることなく一貫したAPIシグネチャを維持できるようになります。

追加されたコードは以下の通りです。

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

net.Errorインターフェースの実装

DNSConfigErrorは、Error()Timeout()Temporary()の3つのメソッドを実装しています。これは、Goのnetパッケージで定義されているnet.Errorインターフェースの要件を満たしています。

  • Error() string: エラーの文字列表現を返します。ここでは「error reading DNS config: [元のエラーメッセージ]」という形式です。
  • Timeout() bool: DNS設定の読み取りエラーは通常タイムアウトではないため、falseを返します。
  • Temporary() bool: DNS設定の読み取りエラーは通常一時的なものではなく、再試行で解決する可能性が低いため、falseを返します。

この移動により、netパッケージ全体のAPIの一貫性が保たれ、特にクロスプラットフォーム開発において、開発者がより予測可能で安定したネットワーク関連の機能を利用できるようになりました。

コアとなるコードの変更箇所

このコミットにおけるコアとなるコードの変更は、DNSConfigError構造体とその関連メソッドの定義が、src/pkg/net/dnsconfig.goからsrc/pkg/net/net.goへ移動した点です。

src/pkg/net/dnsconfig.go から削除された箇所:

--- a/src/pkg/net/dnsconfig.go
+++ b/src/pkg/net/dnsconfig.go
@@ -17,19 +17,6 @@ type dnsConfig struct {
 	rotate   bool     // round robin among servers
 }

-var dnsconfigError error
-
-type DNSConfigError struct {
-	Err error
-}
-
-func (e *DNSConfigError) Error() string {
-	return "error reading DNS config: " + e.Err.Error()
-}
-
-func (e *DNSConfigError) Timeout() bool   { return false }
-func (e *DNSConfigError) Temporary() bool { return false }
-
 // See resolv.conf(5) on a Linux machine.
 // TODO(rsc): Supposed to call uname() and chop the beginning
 // of the host name to get the default search domain.

src/pkg/net/net.go へ追加された箇所:

--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -201,3 +201,15 @@ type UnknownNetworkError string
 func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
 func (e UnknownNetworkError) Temporary() bool { return false }
 func (e UnknownNetworkError) Timeout() bool   { return false }
+
+// DNSConfigError represents an error reading the machine's DNS configuration.
+type DNSConfigError struct {
+	Err error
+}
+
+func (e *DNSConfigError) Error() string {
+	return "error reading DNS config: " + e.Err.Error()
+}
+
+func (e *DNSConfigError) Timeout() bool   { return false }
+func (e *DNSConfigError) Temporary() bool { return false }

コアとなるコードの解説

DNSConfigErrorは、Goのnetパッケージにおいて、システムのDNS設定(例: /etc/resolv.conf)を読み込む際に発生するエラーを表すカスタムエラー型です。この型は、Goのエラーハンドリングの慣習に従い、errorインターフェースを実装しています。

type DNSConfigError struct { Err error }

この行は、DNSConfigErrorという新しい構造体を定義しています。この構造体は、Errという名前のフィールドを一つ持ち、その型は組み込みのerrorインターフェースです。これにより、DNSConfigErrorは、DNS設定の読み込み中に発生した具体的な下位のエラー(例えば、ファイルが見つからない、読み取り権限がないなど)を内部に保持することができます。

func (e *DNSConfigError) Error() string { return "error reading DNS config: " + e.Err.Error() }

これは、errorインターフェースのError()メソッドの実装です。このメソッドは、エラーに関する人間が読める文字列を返します。DNSConfigErrorの場合、"error reading DNS config: "という固定のプレフィックスに、内部に保持しているe.Err(元のエラー)のError()メソッドが返す文字列を連結して返します。これにより、ユーザーはDNS設定の読み込み中にエラーが発生したことと、その具体的な原因の両方を把握できます。

func (e *DNSConfigError) Timeout() bool { return false }

これは、net.ErrorインターフェースのTimeout()メソッドの実装です。このメソッドは、エラーがネットワーク操作のタイムアウトによって引き起こされた場合にtrueを返します。DNS設定の読み込みは通常、ローカルファイルシステムからの操作であり、ネットワークタイムアウトとは直接関係がないため、このメソッドは常にfalseを返します。

func (e *DNSConfigError) Temporary() bool { return false }

これは、net.ErrorインターフェースのTemporary()メソッドの実装です。このメソッドは、エラーが一時的なものであり、操作を再試行することで成功する可能性がある場合にtrueを返します。DNS設定の読み込みエラーは、設定ファイルが存在しない、フォーマットが不正である、権限がないなど、永続的な問題に起因することが多いため、このメソッドは常にfalseを返します。つまり、再試行しても同じエラーが発生する可能性が高いことを示唆しています。

これらのメソッドをnet.goに移動することで、DNSConfigErrorはGoがサポートするすべてのプラットフォームで一貫して利用可能なエラー型となり、netパッケージのAPIの統一性とポータビリティが向上しました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード
  • Go言語のエラーハンドリングに関する一般的な情報源
  • DNSおよび/etc/resolv.confに関する一般的な情報源
  • net.Errorインターフェースに関する情報源
  • Go言語のクロスプラットフォーム開発に関する情報源
  • https://pkg.go.dev/net#Error (Go net.Errorインターフェースの定義)
  • https://pkg.go.dev/net#DNSConfigError (Go net.DNSConfigErrorの現在の定義)
  • https://go.dev/blog/go1.13-errors (Go 1.13以降のエラーハンドリングに関するブログ記事)