[インデックス 13009] ファイルの概要
このコミットは、Go言語の標準ライブラリos
パッケージにおけるPlan 9オペレーティングシステム固有の実装を、Go 1のAPI仕様に準拠させるための変更を含んでいます。具体的には、内部で使用される構造体や関数の可視性を調整し、エラーハンドリングを標準化しています。
コミット
os: Plan 9におけるGo 1 APIへの準拠
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/90626864dc965627590232adbed84949e3ba0e06
元コミット内容
os: conform to Go 1 API on Plan 9
R=golang-dev, r, bradfitz, r
CC=golang-dev
https://golang.org/cl/6117062
変更の背景
このコミットは、Go言語がバージョン1.0のリリースに向けてAPIの安定化を進めていた時期に行われたものです。Go 1のリリースでは、将来にわたって互換性を保証する安定したAPIセットを提供することが目標とされていました。そのため、Goの標準ライブラリ全体でAPIの命名規則、エラー処理、型定義などが厳密にレビューされ、必要に応じて変更が加えられました。
この特定のコミットは、os
パッケージのPlan 9固有の実装が、Go 1のAPIガイドラインに完全に準拠していることを確認するためのものです。主な変更点は、外部に公開すべきでない内部的な型や関数を非公開(unexported)にし、エラーの返却方法をGo 1で推奨される形式に統一することにあります。これにより、Goのos
パッケージがPlan 9環境においても、他のサポートされるOSと同様に一貫した振る舞いとAPIを提供できるようになります。
前提知識の解説
Go言語のAPI可視性(Exported vs. Unexported)
Go言語では、識別子(変数、関数、構造体、インターフェースなど)の最初の文字が大文字である場合、その識別子はパッケージ外からアクセス可能な「エクスポートされた(exported)」ものとなります。一方、最初の文字が小文字である場合、その識別子はパッケージ内でのみアクセス可能な「非エクスポートされた(unexported)」もの、つまり内部的な実装詳細となります。Go 1のAPI安定化では、ユーザーが直接利用すべきでない内部的な型や関数は非エクスポート化され、APIのシンプルさと安定性が追求されました。
Plan 9オペレーティングシステム
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの概念をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するという思想を持っています。Go言語は、その設計思想の一部をPlan 9から継承しており、初期からPlan 9に対するサポートが提供されていました。このコミットは、GoがPlan 9環境で適切に動作し、かつGo 1のAPI規約に沿っていることを保証するものです。
os
パッケージ
Goの標準ライブラリのos
パッケージは、オペレーティングシステムとの相互作用のための機能を提供します。これには、ファイル操作、ディレクトリ操作、プロセス管理、環境変数へのアクセスなどが含まれます。このパッケージは、異なるOS間で可能な限り一貫したインターフェースを提供するように設計されていますが、内部的には各OS固有の実装(例: dir_plan9.go
, file_plan9.go
など)を持っています。
syscall
パッケージ
syscall
パッケージは、低レベルのオペレーティングシステムコールへのプリミティブなインターフェースを提供します。os
パッケージのような高レベルの抽象化された機能の多くは、内部的にsyscall
パッケージを利用しています。このコミットでは、エラーの表現にsyscall
パッケージで定義されているエラーコード(例: syscall.EPLAN9
)が使用されています。
FileInfo
インターフェース
os.FileInfo
インターフェースは、ファイルに関する情報(名前、サイズ、パーミッション、最終更新時刻など)を抽象的に表現するためのものです。os.Stat
やos.Lstat
などの関数がこのインターフェースを実装した型を返します。
PathError
およびLinkError
Goのos
パッケージでは、ファイルパスに関連する操作でエラーが発生した場合に、*os.PathError
型のエラーを返すことが一般的です。これは、エラーが発生した操作、関連するパス、および根本的なエラーを構造化して提供します。同様に、リンク操作(ハードリンク、シンボリックリンク)でエラーが発生した場合は*os.LinkError
が返されます。これらの特定のエラー型を返すことは、Go 1 APIの重要な側面であり、エラーハンドリングの予測可能性を高めます。
技術的詳細
このコミットで行われた主要な技術的変更は以下の通りです。
-
内部構造体と関数の非エクスポート化:
src/pkg/os/dir_plan9.go
において、公開されていたDir
構造体がdir
に、Qid
構造体がqid
に、UnmarshalDir
関数がunmarshalDir
にそれぞれリネームされました。これにより、これらの型と関数はos
パッケージの外部からは直接アクセスできなくなり、内部実装の詳細として扱われるようになりました。これはGo 1のAPI設計原則に沿った変更であり、外部APIの安定性を高めます。- 関連して、これらの型を使用していた他のファイル(
file_plan9.go
,stat_plan9.go
)も、新しい非エクスポート名を使用するように更新されています。
-
エラーハンドリングの標準化:
src/pkg/os/file_plan9.go
において、これまでErrPlan9
というカスタムエラーが返されていた箇所が、syscall.EPLAN9
(Plan 9固有のシステムコールエラー)や、より具体的な*os.PathError
、*os.LinkError
を返すように変更されました。- 例えば、
Link
,Symlink
,Readlink
,Chown
,Lchown
,File.Chown
といった関数は、単にErrPlan9
を返すのではなく、&LinkError{...}
や&PathError{...}
といったGo 1で推奨される構造化されたエラー型を返すようになりました。これにより、エラーの種類と発生コンテキストがより明確になります。 Stat
やTruncate
などの関数コメントに「If there is an error, it will be of type*PathError
.」といったエラー型の明示的な記述が追加され、APIの振る舞いがより明確になりました。
-
PathListSeparator
の明確化:src/pkg/os/path_plan9.go
において、PathListSeparator
の定義が0
から'\000'
へと変更されました。これは、ヌル文字をより明示的に表現するための変更であり、コードの可読性と正確性を向上させます。
これらの変更は、Go 1のAPIが提供する一貫性と予測可能性を、Plan 9環境においても実現するための重要なステップです。
コアとなるコードの変更箇所
src/pkg/os/dir_plan9.go
--- a/src/pkg/os/dir_plan9.go
+++ b/src/pkg/os/dir_plan9.go
@@ -48,7 +48,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
if m < syscall.STATFIXLEN {
return result, &PathError{"readdir", file.name, errShortStat}
}
- dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
+ dir, e := unmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
if e != nil {
return result, &PathError{"readdir", file.name, e}
}
@@ -73,12 +73,12 @@ func (file *File) readdirnames(n int) (names []string, err error) {
return
}
-type Dir struct {
+type dir struct {
// system-modified data
Type uint16 // server type
Dev uint32 // server subtype
// file data
- Qid Qid // unique id from server
+ Qid qid // unique id from server
Mode uint32 // permissions
Atime uint32 // last read time
Mtime uint32 // last write time
@@ -89,16 +89,16 @@ type Dir struct {
Muid string // last modifier name
}
-type Qid struct {
+type qid struct {
Path uint64 // the file server's unique identification for the file
Vers uint32 // version number for given Path
Type uint8 // the type of the file (syscall.QTDIR for example)
}
-var nullDir = Dir{
+var nullDir = dir{
^uint16(0),
^uint32(0),
- Qid{^uint64(0), ^uint32(0), ^uint8(0)},
+ qid{^uint64(0), ^uint32(0), ^uint8(0)},
^uint32(0),
^uint32(0),
^uint32(0),
@@ -111,12 +111,12 @@ var nullDir = Dir{
// Null assigns members of d with special "don't care" values indicating
// they should not be written by syscall.Wstat.
-func (d *Dir) Null() {
+func (d *dir) Null() {
*d = nullDir
}
// pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b.
-func pdir(b []byte, d *Dir) []byte {
+func pdir(b []byte, d *dir) []byte {
n := len(b)
b = pbit16(b, 0) // length, filled in later
b = pbit16(b, d.Type)
@@ -134,9 +134,9 @@ func pdir(b []byte, d *Dir) []byte {
return b
}
-// UnmarshalDir reads a 9P Stat message from a 9P protocol message stored in b,
-// returning the corresponding Dir struct.\n-func UnmarshalDir(b []byte) (d *Dir, err error) {
+// unmarshalDir reads a 9P Stat message from a 9P protocol message stored in b,
+// returning the corresponding dir struct.\n+func unmarshalDir(b []byte) (d *dir, err error) {
n := uint16(0)
n, b = gbit16(b)
@@ -144,7 +144,7 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
return nil, errBadStat
}
- d = new(Dir)
+ d = new(dir)
d.Type, b = gbit16(b)
d.Dev, b = gbit32(b)
d.Qid, b = gqid(b)
@@ -165,17 +165,17 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
}
// gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b,
-// returning the corresponding Qid struct and the remaining slice of b.\n-func gqid(b []byte) (Qid, []byte) {
-// var q Qid
+// returning the corresponding qid struct and the remaining slice of b.\n+func gqid(b []byte) (qid, []byte) {
+// var q qid
q.Path, b = gbit64(b)
q.Vers, b = gbit32(b)
q.Type, b = gbit8(b)
return q, b
}
-// pqid appends a Qid struct q to a 9P message b.\n-func pqid(b []byte, q Qid) []byte {
+// pqid appends a qid struct q to a 9P message b.\n+func pqid(b []byte, q qid) []byte {
b = pbit64(b, q.Path)
b = pbit32(b, q.Vers)
b = pbit8(b, q.Type)
src/pkg/os/file_plan9.go
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -338,32 +340,42 @@ func Pipe() (r *File, w *File, err error) {
// not supported on Plan 9
-// Link creates a hard link.\n+// Link creates newname as a hard link to the oldname file.\n // If there is an error, it will be of type *LinkError.\n func Link(oldname, newname string) error {
-\treturn &LinkError{"link", oldname, newname, ErrPlan9}\n+\treturn &LinkError{"link", oldname, newname, syscall.EPLAN9}\n }\n \n // Symlink creates newname as a symbolic link to oldname.\n // If there is an error, it will be of type *LinkError.\n func Symlink(oldname, newname string) error {
-\treturn &LinkError{"symlink", oldname, newname, ErrPlan9}\n+\treturn &LinkError{"symlink", oldname, newname, syscall.EPLAN9}\n }\n \n+// Readlink returns the destination of the named symbolic link.\n+// If there is an error, it will be of type *PathError.\n func Readlink(name string) (string, error) {
-\treturn "", ErrPlan9\n+\treturn "", &PathError{"readlink", name, syscall.EPLAN9}\n }\n \n+// Chown changes the numeric uid and gid of the named file.\n+// If the file is a symbolic link, it changes the uid and gid of the link's target.\n+// If there is an error, it will be of type *PathError.\n func Chown(name string, uid, gid int) error {
-\treturn ErrPlan9\n+\treturn &PathError{"chown", name, syscall.EPLAN9}\n }\n \n+// Lchown changes the numeric uid and gid of the named file.\n+// If the file is a symbolic link, it changes the uid and gid of the file itself.\n+// If there is an error, it will be of type *PathError.\n func Lchown(name string, uid, gid int) error {
-\treturn ErrPlan9\n+\treturn &PathError{"lchown", name, syscall.EPLAN9}\n }\n \n+// Chown changes the numeric uid and gid of the named file.\n+// If there is an error, it will be of type *PathError.\n func (f *File) Chown(uid, gid int) error {
-\treturn ErrPlan9\n+\treturn &PathError{"chown", f.name, syscall.EPLAN9}\n }\n```
### `src/pkg/os/path_plan9.go`
```diff
--- a/src/pkg/os/path_plan9.go
+++ b/src/pkg/os/path_plan9.go
@@ -5,8 +5,8 @@
package os
const (
- PathSeparator = '/' // OS-specific path separator
- PathListSeparator = 0 // OS-specific path list separator
+ PathSeparator = '/' // OS-specific path separator
+ PathListSeparator = '\000' // OS-specific path list separator
)
// IsPathSeparator returns true if c is a directory separator character.
コアとなるコードの解説
内部構造体と関数の非エクスポート化 (Dir
-> dir
, Qid
-> qid
, UnmarshalDir
-> unmarshalDir
)
Go言語では、パッケージの外部に公開するAPIは、その識別子を大文字で始めるという慣習があります。このコミットでは、Dir
、Qid
、UnmarshalDir
といった識別子が小文字のdir
、qid
、unmarshalDir
に変更されました。これは、これらの型や関数がos
パッケージのPlan 9固有の実装の詳細であり、パッケージの外部から直接利用されることを意図していないためです。
Go 1のAPI安定化の目標の一つは、公開APIを最小限に保ち、内部実装の変更が外部のコードに影響を与えないようにすることでした。これらの変更は、その原則に則ったものであり、os
パッケージのPlan 9実装の内部構造を隠蔽し、よりクリーンで安定した公開APIを提供することに貢献しています。
エラーハンドリングの標準化 (ErrPlan9
から*PathError
/*LinkError
/syscall.EPLAN9
へ)
以前は、Plan 9でサポートされていない操作に対して一律にErrPlan9
というカスタムエラーが返されていました。しかし、Go 1のAPIでは、エラーの種類に応じて特定の構造化されたエラー型(例: *os.PathError
や*os.LinkError
)を返すことが推奨されています。これにより、エラーを処理する側は、エラーの発生原因やコンテキストをより詳細に把握し、適切なエラーハンドリングを行うことができます。
このコミットでは、Link
, Symlink
, Readlink
, Chown
, Lchown
, File.Chown
といった関数が、それぞれの操作に対応する*LinkError
や*PathError
を返すように変更されました。これらのエラー型は、エラーが発生した操作名、関連するファイルパス、そして根本的なシステムコールエラー(この場合はsyscall.EPLAN9
)を含んでいます。これにより、エラーメッセージがより情報豊富になり、デバッグが容易になります。
また、Stat
やTruncate
などの関数に、返されるエラーの型に関するコメントが追加されたことも重要です。これは、APIのドキュメントを改善し、開発者が関数の振る舞いをより正確に理解できるようにするためのものです。
PathListSeparator
の明確化
PathListSeparator
は、環境変数PATH
のように、複数のパスを区切るために使用される文字を定義します。Plan 9では、このセパレータはヌル文字(\000
)です。以前の定義では0
とされていましたが、これは数値リテラルであり、文字としてのヌル文字をより明確に表現するために'\000'
に変更されました。これは機能的な変更というよりも、コードの意図をより正確に表現するための改善です。
これらの変更は全体として、Go 1のAPIの堅牢性、一貫性、および使いやすさを向上させることを目的としています。
関連リンク
- Go CL 6117062: https://golang.org/cl/6117062
参考にした情報源リンク
- Go 1 Release Notes: https://go.dev/doc/go1
- Go Language Specification (Effective Go - Naming): https://go.dev/doc/effective_go#names
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Go
os
package documentation: https://pkg.go.dev/os - Go
syscall
package documentation: https://pkg.go.dev/syscall - Go
os.PathError
documentation: https://pkg.go.dev/os#PathError - Go
os.LinkError
documentation: https://pkg.go.dev/os#LinkError
[インデックス 13009] ファイルの概要
このコミットは、Go言語の標準ライブラリos
パッケージにおけるPlan 9オペレーティングシステム固有の実装を、Go 1のAPI仕様に準拠させるための変更を含んでいます。具体的には、内部で使用される構造体や関数の可視性を調整し、エラーハンドリングを標準化しています。
コミット
os: Plan 9におけるGo 1 APIへの準拠
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/90626864dc965627590232adbed84949e3ba0e06
元コミット内容
os: conform to Go 1 API on Plan 9
R=golang-dev, r, bradfitz, r
CC=golang-dev
https://golang.org/cl/6117062
変更の背景
このコミットは、Go言語がバージョン1.0のリリースに向けてAPIの安定化を進めていた時期に行われたものです。Go 1のリリースでは、将来にわたって互換性を保証する安定したAPIセットを提供することが目標とされていました。そのため、Goの標準ライブラリ全体でAPIの命名規則、エラー処理、型定義などが厳密にレビューされ、必要に応じて変更が加えられました。
この特定のコミットは、os
パッケージのPlan 9固有の実装が、Go 1のAPIガイドラインに完全に準拠していることを確認するためのものです。主な変更点は、外部に公開すべきでない内部的な型や関数を非公開(unexported)にし、エラーの返却方法をGo 1で推奨される形式に統一することにあります。これにより、Goのos
パッケージがPlan 9環境においても、他のサポートされるOSと同様に一貫した振る舞いとAPIを提供できるようになります。
前提知識の解説
Go言語のAPI可視性(Exported vs. Unexported)
Go言語では、識別子(変数、関数、構造体、インターフェースなど)の最初の文字が大文字である場合、その識別子はパッケージ外からアクセス可能な「エクスポートされた(exported)」ものとなります。一方、最初の文字が小文字である場合、その識別子はパッケージ内でのみアクセス可能な「非エクスポートされた(unexported)」もの、つまり内部的な実装詳細となります。Go 1のAPI安定化では、ユーザーが直接利用すべきでない内部的な型や関数は非エクスポート化され、APIのシンプルさと安定性が追求されました。
Plan 9オペレーティングシステム
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの概念をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するという思想を持っています。Go言語は、その設計思想の一部をPlan 9から継承しており、初期からPlan 9に対するサポートが提供されていました。このコミットは、GoがPlan 9環境で適切に動作し、かつGo 1のAPI規約に沿っていることを保証するものです。
os
パッケージ
Goの標準ライブラリのos
パッケージは、オペレーティングシステムとの相互作用のための機能を提供します。これには、ファイル操作、ディレクトリ操作、プロセス管理、環境変数へのアクセスなどが含まれます。このパッケージは、異なるOS間で可能な限り一貫したインターフェースを提供するように設計されていますが、内部的には各OS固有の実装(例: dir_plan9.go
, file_plan9.go
など)を持っています。
syscall
パッケージ
syscall
パッケージは、低レベルのオペレーティングシステムコールへのプリミティブなインターフェースを提供します。os
パッケージのような高レベルの抽象化された機能の多くは、内部的にsyscall
パッケージを利用しています。このコミットでは、エラーの表現にsyscall
パッケージで定義されているエラーコード(例: syscall.EPLAN9
)が使用されています。
FileInfo
インターフェース
os.FileInfo
インターフェースは、ファイルに関する情報(名前、サイズ、パーミッション、最終更新時刻など)を抽象的に表現するためのものです。os.Stat
やos.Lstat
などの関数がこのインターフェースを実装した型を返します。
PathError
およびLinkError
Goのos
パッケージでは、ファイルパスに関連する操作でエラーが発生した場合に、*os.PathError
型のエラーを返すことが一般的です。これは、エラーが発生した操作、関連するパス、および根本的なエラーを構造化して提供します。同様に、リンク操作(ハードリンク、シンボリックリンク)でエラーが発生した場合は*os.LinkError
が返されます。これらの特定のエラー型を返すことは、Go 1 APIの重要な側面であり、エラーハンドリングの予測可能性を高めます。
技術的詳細
このコミットで行われた主要な技術的変更は以下の通りです。
-
内部構造体と関数の非エクスポート化:
src/pkg/os/dir_plan9.go
において、公開されていたDir
構造体がdir
に、Qid
構造体がqid
に、UnmarshalDir
関数がunmarshalDir
にそれぞれリネームされました。これにより、これらの型と関数はos
パッケージの外部からは直接アクセスできなくなり、内部実装の詳細として扱われるようになりました。これはGo 1のAPI設計原則に沿った変更であり、外部APIの安定性を高めます。- 関連して、これらの型を使用していた他のファイル(
file_plan9.go
,stat_plan9.go
)も、新しい非エクスポート名を使用するように更新されています。
-
エラーハンドリングの標準化:
src/pkg/os/file_plan9.go
において、これまでErrPlan9
というカスタムエラーが返されていた箇所が、syscall.EPLAN9
(Plan 9固有のシステムコールエラー)や、より具体的な*os.PathError
、*os.LinkError
を返すように変更されました。- 例えば、
Link
,Symlink
,Readlink
,Chown
,Lchown
,File.Chown
といった関数は、単にErrPlan9
を返すのではなく、&LinkError{...}
や&PathError{...}
といったGo 1で推奨される構造化されたエラー型を返すようになりました。これにより、エラーの種類と発生コンテキストがより明確になります。 Stat
やTruncate
などの関数コメントに「If there is an error, it will be of type*PathError
.」といったエラー型の明示的な記述が追加され、APIの振る舞いがより明確になりました。
-
PathListSeparator
の明確化:src/pkg/os/path_plan9.go
において、PathListSeparator
の定義が0
から'\000'
へと変更されました。これは、ヌル文字をより明示的に表現するための変更であり、コードの可読性と正確性を向上させます。
これらの変更は、Go 1のAPIが提供する一貫性と予測可能性を、Plan 9環境においても実現するための重要なステップです。
コアとなるコードの変更箇所
src/pkg/os/dir_plan9.go
--- a/src/pkg/os/dir_plan9.go
+++ b/src/pkg/os/dir_plan9.go
@@ -48,7 +48,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
if m < syscall.STATFIXLEN {
return result, &PathError{"readdir", file.name, errShortStat}
}
- dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
+ dir, e := unmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
if e != nil {
return result, &PathError{"readdir", file.name, e}
}
@@ -73,12 +73,12 @@ func (file *File) readdirnames(n int) (names []string, err error) {
return
}
-type Dir struct {
+type dir struct {
// system-modified data
Type uint16 // server type
Dev uint32 // server subtype
// file data
- Qid Qid // unique id from server
+ Qid qid // unique id from server
Mode uint32 // permissions
Atime uint32 // last read time
Mtime uint32 // last write time
@@ -89,16 +89,16 @@ type Dir struct {
Muid string // last modifier name
}
-type Qid struct {
+type qid struct {
Path uint64 // the file server's unique identification for the file
Vers uint32 // version number for given Path
Type uint8 // the type of the file (syscall.QTDIR for example)
}
-var nullDir = Dir{
+var nullDir = dir{
^uint16(0),
^uint32(0),
- Qid{^uint64(0), ^uint32(0), ^uint8(0)},
+ qid{^uint64(0), ^uint32(0), ^uint8(0)},
^uint32(0),
^uint32(0),
^uint32(0),
@@ -111,12 +111,12 @@ var nullDir = Dir{
// Null assigns members of d with special "don't care" values indicating
// they should not be written by syscall.Wstat.
-func (d *Dir) Null() {
+func (d *dir) Null() {
*d = nullDir
}
// pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b.
-func pdir(b []byte, d *Dir) []byte {
+func pdir(b []byte, d *dir) []byte {
n := len(b)
b = pbit16(b, 0) // length, filled in later
b = pbit16(b, d.Type)
@@ -134,9 +134,9 @@ func pdir(b []byte, d *Dir) []byte {
return b
}
-// UnmarshalDir reads a 9P Stat message from a 9P protocol message stored in b,
-// returning the corresponding Dir struct.\n-func UnmarshalDir(b []byte) (d *Dir, err error) {
+// unmarshalDir reads a 9P Stat message from a 9P protocol message stored in b,
+// returning the corresponding dir struct.\n+func unmarshalDir(b []byte) (d *dir, err error) {
n := uint16(0)
n, b = gbit16(b)
@@ -144,7 +144,7 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
return nil, errBadStat
}
- d = new(Dir)
+ d = new(dir)
d.Type, b = gbit16(b)
d.Dev, b = gbit32(b)
d.Qid, b = gqid(b)
@@ -165,17 +165,17 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
}
// gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b,
-// returning the corresponding Qid struct and the remaining slice of b.\n-func gqid(b []byte) (Qid, []byte) {
-// var q Qid
+// returning the corresponding qid struct and the remaining slice of b.\n+func gqid(b []byte) (qid, []byte) {
+// var q qid
q.Path, b = gbit64(b)
q.Vers, b = gbit32(b)
q.Type, b = gbit8(b)
return q, b
}
-// pqid appends a Qid struct q to a 9P message b.\n-func pqid(b []byte, q Qid) []byte {
+// pqid appends a qid struct q to a 9P message b.\n+func pqid(b []byte, q qid) []byte {
b = pbit64(b, q.Path)
b = pbit32(b, q.Vers)
b = pbit8(b, q.Type)
src/pkg/os/file_plan9.go
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -338,32 +340,42 @@ func Pipe() (r *File, w *File, err error) {
// not supported on Plan 9
-// Link creates a hard link.\n+// Link creates newname as a hard link to the oldname file.\n // If there is an error, it will be of type *LinkError.\n func Link(oldname, newname string) error {
-\treturn &LinkError{"link", oldname, newname, ErrPlan9}\n+\treturn &LinkError{"link", oldname, newname, syscall.EPLAN9}\n }\n \n // Symlink creates newname as a symbolic link to oldname.\n // If there is an error, it will be of type *LinkError.\n func Symlink(oldname, newname string) error {
-\treturn &LinkError{"symlink", oldname, newname, ErrPlan9}\n+\treturn &LinkError{"symlink", oldname, newname, syscall.EPLAN9}\n }\n \n+// Readlink returns the destination of the named symbolic link.\n+// If there is an error, it will be of type *PathError.\n func Readlink(name string) (string, error) {
-\treturn "", ErrPlan9\n+\treturn "", &PathError{"readlink", name, syscall.EPLAN9}\n }\n \n+// Chown changes the numeric uid and gid of the named file.\n+// If the file is a symbolic link, it changes the uid and gid of the link's target.\n+// If there is an error, it will be of type *PathError.\n func Chown(name string, uid, gid int) error {
-\treturn ErrPlan9\n+\treturn &PathError{"chown", name, syscall.EPLAN9}\n }\n \n+// Lchown changes the numeric uid and gid of the named file.\n+// If the file is a symbolic link, it changes the uid and gid of the file itself.\n+// If there is an error, it will be of type *PathError.\n func Lchown(name string, uid, gid int) error {
-\treturn ErrPlan9\n+\treturn &PathError{"lchown", name, syscall.EPLAN9}\n }\n \n+// Chown changes the numeric uid and gid of the named file.\n+// If there is an error, it will be of type *PathError.\n func (f *File) Chown(uid, gid int) error {
-\treturn ErrPlan9\n+\treturn &PathError{"chown", f.name, syscall.EPLAN9}\n }\n```
### `src/pkg/os/path_plan9.go`
```diff
--- a/src/pkg/os/path_plan9.go
+++ b/src/pkg/os/path_plan9.go
@@ -5,8 +5,8 @@
package os
const (
- PathSeparator = '/' // OS-specific path separator
- PathListSeparator = 0 // OS-specific path list separator
+ PathSeparator = '/' // OS-specific path separator
+ PathListSeparator = '\000' // OS-specific path list separator
)
// IsPathSeparator returns true if c is a directory separator character.
コアとなるコードの解説
内部構造体と関数の非エクスポート化 (Dir
-> dir
, Qid
-> qid
, UnmarshalDir
-> unmarshalDir
)
Go言語では、パッケージの外部に公開するAPIは、その識別子を大文字で始めるという慣習があります。このコミットでは、Dir
、Qid
、UnmarshalDir
といった識別子が小文字のdir
、qid
、unmarshalDir
に変更されました。これは、これらの型や関数がos
パッケージのPlan 9固有の実装の詳細であり、パッケージの外部から直接利用されることを意図していないためです。
Go 1のAPI安定化の目標の一つは、公開APIを最小限に保ち、内部実装の変更が外部のコードに影響を与えないようにすることでした。これらの変更は、その原則に則ったものであり、os
パッケージのPlan 9実装の内部構造を隠蔽し、よりクリーンで安定した公開APIを提供することに貢献しています。
エラーハンドリングの標準化 (ErrPlan9
から*PathError
/*LinkError
/syscall.EPLAN9
へ)
以前は、Plan 9でサポートされていない操作に対して一律にErrPlan9
というカスタムエラーが返されていました。しかし、Go 1のAPIでは、エラーの種類に応じて特定の構造化されたエラー型(例: *os.PathError
や*os.LinkError
)を返すことが推奨されています。これにより、エラーを処理する側は、エラーの発生原因やコンテキストをより詳細に把握し、適切なエラーハンドリングを行うことができます。
このコミットでは、Link
, Symlink
, Readlink
, Chown
, Lchown
, File.Chown
といった関数が、それぞれの操作に対応する*LinkError
や*PathError
を返すように変更されました。これらのエラー型は、エラーが発生した操作名、関連するファイルパス、そして根本的なシステムコールエラー(この場合はsyscall.EPLAN9
)を含んでいます。これにより、エラーメッセージがより情報豊富になり、デバッグが容易になります。
また、Stat
やTruncate
などの関数に、返されるエラーの型に関するコメントが追加されたことも重要です。これは、APIのドキュメントを改善し、開発者が関数の振る舞いをより正確に理解できるようにするためのものです。
PathListSeparator
の明確化
PathListSeparator
は、環境変数PATH
のように、複数のパスを区切るために使用される文字を定義します。Plan 9では、このセパレータはヌル文字(\000
)です。以前の定義では0
とされていましたが、これは数値リテラルであり、文字としてのヌル文字をより明確に表現するために'\000'
に変更されました。これは機能的な変更というよりも、コードの意図をより正確に表現するための改善です。
これらの変更は全体として、Go 1のAPIの堅牢性、一貫性、および使いやすさを向上させることを目的としています。
関連リンク
- Go CL 6117062: https://golang.org/cl/6117062
参考にした情報源リンク
- Go 1 Release Notes: https://go.dev/doc/go1
- Go Language Specification (Effective Go - Naming): https://go.dev/doc/effective_go#names
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Go
os
package documentation: https://pkg.go.dev/os - Go
syscall
package documentation: https://pkg.go.dev/syscall - Go
os.PathError
documentation: https://pkg.go.dev/os#PathError - Go
os.LinkError
documentation: https://pkg.go.dev/os#LinkError