[インデックス 14890] ファイルの概要
このコミットは、Go言語の標準ライブラリであるsyscall
パッケージ内のソケットコントロールメッセージ(Socket Control Messages、またはAncillary Data)を扱うコードの簡素化を目的としています。具体的には、src/pkg/syscall/sockcmsg_linux.go
とsrc/pkg/syscall/sockcmsg_unix.go
の2つのファイルが変更されています。これらのファイルは、LinuxおよびUnix系システムにおけるソケットを介した補助データの送受信、特にプロセス間でファイルディスクリプタや認証情報をやり取りする機能を提供します。
コミット
このコミットは、ソケットコントロールメッセージを扱うコードの可読性とGo言語のイディオムへの準拠を向上させるためのリファクタリングです。機能的な変更は含まれておらず、主に変数名の短縮とコードの記述方法の簡素化が行われています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c241f696f87a1d0aaf1cc28eb6383e73184ef837
元コミット内容
commit c241f696f87a1d0aaf1cc28eb6383e73184ef837
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Tue Jan 15 08:52:22 2013 +0900
syscall: simplify socket control messages
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7016044
変更の背景
この変更の背景には、Go言語のコードベース全体における一貫性と可読性の向上という一般的な目標があります。特に、syscall
パッケージのような低レベルで複雑なコードにおいては、簡潔でイディオムに沿った記述が重要になります。
このコミットは、以下の点を改善するために行われました。
- 変数名の簡素化:
buf
をb
に、cmsg
をh
に、msg
をm
に短縮することで、Go言語の慣習(短い変数名を好む傾向)に合わせ、コードの視覚的なノイズを減らしています。これにより、コードがより簡潔になり、一目で何が行われているかを把握しやすくなります。 - 冗長なインポートの削除:
unsafe
パッケージのインポートが重複していた箇所が削除されました。これは、Goのツールが自動的にインポートを管理するようになったり、コンパイラが不要なインポートを検出するようになったりした結果として行われる一般的なクリーンアップです。 - 構造体初期化の簡潔化:
SocketControlMessage
構造体の初期化が、より直接的なリテラル形式で行われるようになりました。これにより、コードの行数が減り、意図が明確になります。
これらの変更は、機能的な振る舞いを一切変更することなく、コードの保守性と理解しやすさを向上させるための純粋なリファクタリングです。
前提知識の解説
Go言語のsyscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、ファイル操作、プロセス管理、ネットワーク通信など、OSカーネルが提供する基本的な機能にアクセスできます。このパッケージは、Goの標準ライブラリの他の高レベルなパッケージ(例: net
、os
)の基盤としても機能します。低レベルな操作のため、unsafe
パッケージと組み合わせてC言語の構造体やメモリレイアウトを直接扱うことがよくあります。
ソケットコントロールメッセージ (Socket Control Messages / Ancillary Data)
ソケットコントロールメッセージは、Unixドメインソケット(または一部の他のソケットタイプ)を介して、通常のデータストリームとは別に補助的な情報を送受信するためのメカニズムです。これはsendmsg()
およびrecvmsg()
システムコールによって処理されます。主な用途は以下の通りです。
- ファイルディスクリプタの受け渡し (
SCM_RIGHTS
): プロセス間でオープンされたファイルディスクリプタ(ソケット、ファイル、パイプなど)を安全に受け渡すことができます。これにより、子プロセスが親プロセスからリソースを継承したり、異なるプロセス間でリソースを共有したりすることが可能になります。 - 認証情報の受け渡し (
SCM_CREDENTIALS
): 送信元のプロセスのユーザーID、グループID、プロセスIDなどの認証情報を相手プロセスに渡すことができます。これは、Unixドメインソケットを介したローカルな認証メカニズムとして利用されます。
これらのメッセージは、Cmsghdr
構造体とそれに続くデータで構成されます。
Cmsghdr
構造体
Cmsghdr
は、ソケットコントロールメッセージのヘッダを定義する構造体です。主要なフィールドは以下の通りです。
cmsg_len
: コントロールメッセージ全体の長さ(ヘッダとデータを含む)。cmsg_level
: メッセージのプロトコルレベル(例:SOL_SOCKET
)。cmsg_type
: メッセージのタイプ(例:SCM_RIGHTS
、SCM_CREDENTIALS
)。
この構造体は、C言語のAPIと直接やり取りするために、Goのunsafe
パッケージを使ってメモリ上で直接操作されることが一般的です。
unsafe
パッケージとポインタ操作
Go言語は通常、ポインタ演算を制限し、メモリ安全性を重視します。しかし、unsafe
パッケージを使用すると、Goの型システムを迂回して、C言語のようにポインタを直接操作したり、異なる型のポインタ間で変換したりすることが可能になります。syscall
パッケージのようにOSの低レベルなAPIと連携する場合、C言語の構造体とGoのバイトスライス間でデータを効率的にやり取りするために、unsafe.Pointer
やuintptr
を用いたポインタ演算が不可欠となります。
unsafe.Pointer
: 任意の型のポインタを保持できる汎用ポインタ。型チェックを無効にする。uintptr
: ポインタの値を整数として表現する型。ポインタ演算を行う際に使用される。
Goのイディオムとコードスタイル
Go言語には、公式のスタイルガイドやコミュニティで広く受け入れられているコーディング慣習(イディオム)があります。
- 短い変数名: 特にスコープが狭い、または型が明確な変数には、
i
、j
、b
(バイトスライス)、r
(リーダー)、w
(ライター)、err
(エラー)などの短い変数名が好まれます。これにより、コードが簡潔になり、読みやすくなります。 - エラーハンドリング: Goはエラーを戻り値として明示的に返すことを推奨しており、
if err != nil
パターンが一般的です。 - 構造体リテラル: 構造体の初期化には、フィールド名を明示的に指定する構造体リテラルがよく使われます。
このコミットは、これらのGoのイディオムに沿ってコードを改善しています。
技術的詳細
このコミットで行われた変更は、主に以下の3つのカテゴリに分類されます。
-
変数名の変更:
buf
(buffer) ->b
cmsg
(control message header) ->h
msg
(socket control message) ->m
e
(error) ->err
(これはParseSocketControlMessage
関数内のみ) これらの変更は、Go言語の慣習に従い、スコープが限定的で型が明確な変数に対して短い名前を使用するという原則を適用したものです。これにより、コードの行が短くなり、視覚的なノイズが減少し、コードの意図がより迅速に把握できるようになります。
-
冗長な
import "unsafe"
の削除:src/pkg/syscall/sockcmsg_linux.go
とsrc/pkg/syscall/sockcmsg_unix.go
の両方で、import ("unsafe")
という行が削除されています。これは、Goのビルドシステムやリンターが、実際に使用されているパッケージのみをインポートするように最適化された結果、あるいは以前のコードで明示的にインポートされていたものが、Goのバージョンアップに伴い不要になったためと考えられます。unsafe
パッケージは、unsafe.Pointer
やuintptr
がコード内で使用されている限り、自動的にインポートされるため、明示的なインポート文は冗長になります。 -
ParseSocketControlMessage
関数内の構造体初期化の簡潔化:src/pkg/syscall/sockcmsg_unix.go
のParseSocketControlMessage
関数内で、SocketControlMessage
構造体の初期化方法が変更されました。変更前:
m := SocketControlMessage{} m.Header = *h m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)] cmsgs = append(cmsgs, m)
変更後:
m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]} msgs = append(msgs, m)
これは、Goの構造体リテラルを使用して、構造体のフィールドを一度に初期化する、より簡潔な方法です。これにより、コードの行数が減り、
m
がどのように構築されるかがより明確になります。また、エラー変数名もe
からerr
に変更され、Goの標準的なエラー変数名に統一されています。
これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のベストプラクティスとスタイルガイドに沿ってコードベースを改善するためのものです。
コアとなるコードの変更箇所
src/pkg/syscall/sockcmsg_linux.go
--- a/src/pkg/syscall/sockcmsg_linux.go
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -6,33 +6,31 @@
package syscall
-import (
- "unsafe"
-)
+import "unsafe"
// UnixCredentials encodes credentials into a socket control message
// for sending to another process. This can be used for
// authentication.
func UnixCredentials(ucred *Ucred) []byte {
-- buf := make([]byte, CmsgSpace(SizeofUcred))
-- cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
-- cmsg.Level = SOL_SOCKET
-- cmsg.Type = SCM_CREDENTIALS
-- cmsg.SetLen(CmsgLen(SizeofUcred))
-- *((*Ucred)(cmsgData(cmsg))) = *ucred
-- return buf
-+ b := make([]byte, CmsgSpace(SizeofUcred))
-+ h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-+ h.Level = SOL_SOCKET
-+ h.Type = SCM_CREDENTIALS
-+ h.SetLen(CmsgLen(SizeofUcred))
-+ *((*Ucred)(cmsgData(h))) = *ucred
-+ return b
}
// ParseUnixCredentials decodes a socket control message that contains
// credentials in a Ucred structure. To receive such a message, the
// SO_PASSCRED option must be enabled on the socket.
-func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, error) {
-- if msg.Header.Level != SOL_SOCKET {
-+func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
-+ if m.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
-- if msg.Header.Type != SCM_CREDENTIALS {
-+ if m.Header.Type != SCM_CREDENTIALS {
return nil, EINVAL
}
-- ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
-+ ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
return &ucred, nil
}
src/pkg/syscall/sockcmsg_unix.go
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -8,9 +8,7 @@
package syscall
-import (
- "unsafe"
-)
+import "unsafe"
// Round the length of a raw sockaddr up to align it propery.
func cmsgAlignOf(salen int) int {
@@ -38,77 +36,69 @@ func CmsgSpace(datalen int) int {
return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
}
-func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
-- return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
-+func cmsgData(h *Cmsghdr) unsafe.Pointer {
-+ return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
}
-// SocketControlMessage represents a socket control message.
type SocketControlMessage struct {
Header Cmsghdr
Data []byte
}
-func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
-- var (
-- h *Cmsghdr
-- dbuf []byte
-- e error
-- cmsgs []SocketControlMessage
-- )
--
-- for len(buf) >= CmsgLen(0) {
-- h, dbuf, e = socketControlMessageHeaderAndData(buf)
-- if e != nil {
-- break
-- }
-- m := SocketControlMessage{}
-- m.Header = *h
-- m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
-- cmsgs = append(cmsgs, m)
-- buf = buf[cmsgAlignOf(int(h.Len)):]
-+func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
-+ var msgs []SocketControlMessage
-+ for len(b) >= CmsgLen(0) {
-+ h, dbuf, err := socketControlMessageHeaderAndData(b)
-+ if err != nil {
-+ return nil, err
-+ }
-+ m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]}
-+ msgs = append(msgs, m)
-+ b = b[cmsgAlignOf(int(h.Len)):]
}
--
-- return cmsgs, e
-+ return msgs, nil
}
-func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
-- h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
-- if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
-+func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
-+ h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-+ if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
return nil, nil, EINVAL
}
-- return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
-+ return h, b[cmsgAlignOf(SizeofCmsghdr):], nil
}
// UnixRights encodes a set of open file descriptors into a socket
// control message for sending to another process.
func UnixRights(fds ...int) []byte {
datalen := len(fds) * 4
-- buf := make([]byte, CmsgSpace(datalen))
-- cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
-- cmsg.Level = SOL_SOCKET
-- cmsg.Type = SCM_RIGHTS
-- cmsg.SetLen(CmsgLen(datalen))
--
-- data := uintptr(cmsgData(cmsg))
-+ b := make([]byte, CmsgSpace(datalen))
-+ h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-+ h.Level = SOL_SOCKET
-+ h.Type = SCM_RIGHTS
-+ h.SetLen(CmsgLen(datalen))
-+ data := uintptr(cmsgData(h))
for _, fd := range fds {
*(*int32)(unsafe.Pointer(data)) = int32(fd)
data += 4
}
--
-- return buf
-+ return b
}
// ParseUnixRights decodes a socket control message that contains an
// integer array of open file descriptors from another process.
-func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
-- if msg.Header.Level != SOL_SOCKET {
-+func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
-+ if m.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
-- if msg.Header.Type != SCM_RIGHTS {
-+ if m.Header.Type != SCM_RIGHTS {
return nil, EINVAL
}
-- fds := make([]int, len(msg.Data)>>2)
-- for i, j := 0, 0; i < len(msg.Data); i += 4 {
-- fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
-+ fds := make([]int, len(m.Data)>>2)
-+ for i, j := 0, 0; i < len(m.Data); i += 4 {
-+ fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
j++
}
return fds, nil
コアとなるコードの解説
src/pkg/syscall/sockcmsg_linux.go
UnixCredentials
関数:- 変更前:
buf
とcmsg
という変数名を使用していました。 - 変更後:
b
とh
という短い変数名に変更されました。機能的な変更はありません。buf
はバイトスライス、cmsg
はCmsghdr
ポインタを指すため、それぞれb
とh
に短縮されています。
- 変更前:
ParseUnixCredentials
関数:- 変更前: 引数
msg
を使用していました。 - 変更後: 引数
m
という短い変数名に変更されました。関数内部でのmsg.Header.Level
やmsg.Data
へのアクセスもm.Header.Level
やm.Data
に変更されています。機能的な変更はありません。
- 変更前: 引数
src/pkg/syscall/sockcmsg_unix.go
import "unsafe"
の削除:- ファイル冒頭の
import ("unsafe")
が削除されました。これは、Goのコンパイラがコード内でunsafe
パッケージの機能(例:unsafe.Pointer
)が使用されていることを検出すると、自動的にインポートするため、明示的なインポート文が不要になったためです。
- ファイル冒頭の
cmsgData
関数:- 変更前: 引数
cmsg
を使用していました。 - 変更後: 引数
h
という短い変数名に変更されました。機能的な変更はありません。
- 変更前: 引数
ParseSocketControlMessage
関数:- 変更前: 引数
buf
、内部変数h
,dbuf
,e
,cmsgs
を使用していました。SocketControlMessage
の初期化は複数行に分かれていました。 - 変更後: 引数
b
、内部変数h
,dbuf
,err
,msgs
という短い変数名に変更されました。特にエラー変数e
がGoの慣習であるerr
に変更されています。 - 最も顕著な変更は、
SocketControlMessage
構造体の初期化が、m := SocketControlMessage{Header: *h, Data: ...}
という単一行の構造体リテラルに簡潔化された点です。これにより、コードの可読性が向上し、意図がより明確になります。
- 変更前: 引数
socketControlMessageHeaderAndData
関数:- 変更前: 引数
buf
を使用していました。 - 変更後: 引数
b
という短い変数名に変更されました。機能的な変更はありません。
- 変更前: 引数
UnixRights
関数:- 変更前:
buf
とcmsg
という変数名を使用していました。 - 変更後:
b
とh
という短い変数名に変更されました。機能的な変更はありません。
- 変更前:
ParseUnixRights
関数:- 変更前: 引数
msg
を使用していました。 - 変更後: 引数
m
という短い変数名に変更されました。機能的な変更はありません。
- 変更前: 引数
これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のコーディングスタイルとイディオムに沿ってコードをより簡潔で読みやすいものにするためのものです。
関連リンク
- Go言語
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - Linux
sendmsg(2)
man page (ソケットコントロールメッセージに関する詳細): https://man7.org/linux/man-pages/man2/sendmsg.2.html - Linux
cmsg(3)
man page (コントロールメッセージの構造に関する詳細): https://man7.org/linux/man-pages/man3/cmsg.3.html - Go言語のコードレビューガイドライン (変数名の慣習など): https://go.dev/doc/effective_go#names
参考にした情報源リンク
- Go言語の公式ドキュメント
- Linux man pages (sendmsg, cmsg)
- Go言語のコーディングスタイルに関する一般的な情報源
- Gerrit Change-ID:
https://golang.org/cl/7016044
(これはGoプロジェクトのコードレビューシステムへのリンクであり、コミットの詳細な議論や変更の経緯を確認できます。)
[インデックス 14890] ファイルの概要
このコミットは、Go言語の標準ライブラリであるsyscall
パッケージ内のソケットコントロールメッセージ(Socket Control Messages、またはAncillary Data)を扱うコードの簡素化を目的としています。具体的には、src/pkg/syscall/sockcmsg_linux.go
とsrc/pkg/syscall/sockcmsg_unix.go
の2つのファイルが変更されています。これらのファイルは、LinuxおよびUnix系システムにおけるソケットを介した補助データの送受信、特にプロセス間でファイルディスクリプタや認証情報をやり取りする機能を提供します。
コミット
このコミットは、ソケットコントロールメッセージを扱うコードの可読性とGo言語のイディオムへの準拠を向上させるためのリファクタリングです。機能的な変更は含まれておらず、主に変数名の短縮とコードの記述方法の簡素化が行われています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c241f696f87a1d0aaf1cc28eb6383e73184ef837
元コミット内容
commit c241f696f87a1d0aaf1cc28eb6383e73184ef837
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Tue Jan 15 08:52:22 2013 +0900
syscall: simplify socket control messages
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7016044
変更の背景
この変更の背景には、Go言語のコードベース全体における一貫性と可読性の向上という一般的な目標があります。特に、syscall
パッケージのような低レベルで複雑なコードにおいては、簡潔でイディオムに沿った記述が重要になります。
このコミットは、以下の点を改善するために行われました。
- 変数名の簡素化:
buf
をb
に、cmsg
をh
に、msg
をm
に短縮することで、Go言語の慣習(短い変数名を好む傾向)に合わせ、コードの視覚的なノイズを減らしています。これにより、コードがより簡潔になり、一目で何が行われているかを把握しやすくなります。 - 冗長なインポートの削除:
unsafe
パッケージのインポートが重複していた箇所が削除されました。これは、Goのツールが自動的にインポートを管理するようになったり、コンパイラが不要なインポートを検出するようになったりした結果として行われる一般的なクリーンアップです。 - 構造体初期化の簡潔化:
SocketControlMessage
構造体の初期化が、より直接的なリテラル形式で行われるようになりました。これにより、コードの行数が減り、意図が明確になります。
これらの変更は、機能的な振る舞いを一切変更することなく、コードの保守性と理解しやすさを向上させるための純粋なリファクタリングです。
前提知識の解説
Go言語のsyscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、ファイル操作、プロセス管理、ネットワーク通信など、OSカーネルが提供する基本的な機能にアクセスできます。このパッケージは、Goの標準ライブラリの他の高レベルなパッケージ(例: net
、os
)の基盤としても機能します。低レベルな操作のため、unsafe
パッケージと組み合わせてC言語の構造体やメモリレイアウトを直接扱うことがよくあります。
ソケットコントロールメッセージ (Socket Control Messages / Ancillary Data)
ソケットコントロールメッセージは、Unixドメインソケット(または一部の他のソケットタイプ)を介して、通常のデータストリームとは別に補助的な情報を送受信するためのメカニズムです。これはsendmsg()
およびrecvmsg()
システムコールによって処理されます。主な用途は以下の通りです。
- ファイルディスクリプタの受け渡し (
SCM_RIGHTS
): プロセス間でオープンされたファイルディスクリプタ(ソケット、ファイル、パイプなど)を安全に受け渡すことができます。これにより、子プロセスが親プロセスからリソースを継承したり、異なるプロセス間でリソースを共有したりすることが可能になります。 - 認証情報の受け渡し (
SCM_CREDENTIALS
): 送信元のプロセスのユーザーID、グループID、プロセスIDなどの認証情報を相手プロセスに渡すことができます。これは、Unixドメインソケットを介したローカルな認証メカニズムとして利用されます。
これらのメッセージは、Cmsghdr
構造体とそれに続くデータで構成されます。
Cmsghdr
構造体
Cmsghdr
は、ソケットコントロールメッセージのヘッダを定義する構造体です。主要なフィールドは以下の通りです。
cmsg_len
: コントロールメッセージ全体の長さ(ヘッダとデータを含む)。cmsg_level
: メッセージのプロトコルレベル(例:SOL_SOCKET
)。cmsg_type
: メッセージのタイプ(例:SCM_RIGHTS
、SCM_CREDENTIALS
)。
この構造体は、C言語のAPIと直接やり取りするために、Goのunsafe
パッケージを使ってメモリ上で直接操作されることが一般的です。
unsafe
パッケージとポインタ操作
Go言語は通常、ポインタ演算を制限し、メモリ安全性を重視します。しかし、unsafe
パッケージを使用すると、Goの型システムを迂回して、C言語のようにポインタを直接操作したり、異なる型のポインタ間で変換したりすることが可能になります。syscall
パッケージのようにOSの低レベルなAPIと連携する場合、C言語の構造体とGoのバイトスライス間でデータを効率的にやり取りするために、unsafe.Pointer
やuintptr
を用いたポインタ演算が不可欠となります。
unsafe.Pointer
: 任意の型のポインタを保持できる汎用ポインタ。型チェックを無効にする。uintptr
: ポインタの値を整数として表現する型。ポインタ演算を行う際に使用される。
Goのイディオムとコードスタイル
Go言語には、公式のスタイルガイドやコミュニティで広く受け入れられているコーディング慣習(イディオム)があります。
- 短い変数名: 特にスコープが狭い、または型が明確な変数には、
i
、j
、b
(バイトスライス)、r
(リーダー)、w
(ライター)、err
(エラー)などの短い変数名が好まれます。これにより、コードが簡潔になり、読みやすくなります。 - エラーハンドリング: Goはエラーを戻り値として明示的に返すことを推奨しており、
if err != nil
パターンが一般的です。 - 構造体リテラル: 構造体の初期化には、フィールド名を明示的に指定する構造体リテラルがよく使われます。
このコミットは、これらのGoのイディオムに沿ってコードを改善しています。
技術的詳細
このコミットで行われた変更は、主に以下の3つのカテゴリに分類されます。
-
変数名の変更:
buf
(buffer) ->b
cmsg
(control message header) ->h
msg
(socket control message) ->m
e
(error) ->err
(これはParseSocketControlMessage
関数内のみ) これらの変更は、Go言語の慣習に従い、スコープが限定的で型が明確な変数に対して短い名前を使用するという原則を適用したものです。これにより、コードの行が短くなり、視覚的なノイズが減少し、コードの意図がより迅速に把握できるようになります。
-
冗長な
import "unsafe"
の削除:src/pkg/syscall/sockcmsg_linux.go
とsrc/pkg/syscall/sockcmsg_unix.go
の両方で、import ("unsafe")
という行が削除されています。これは、Goのビルドシステムやリンターが、実際に使用されているパッケージのみをインポートするように最適化された結果、あるいは以前のコードで明示的にインポートされていたものが、Goのバージョンアップに伴い不要になったためと考えられます。unsafe
パッケージは、unsafe.Pointer
やuintptr
がコード内で使用されている限り、自動的にインポートされるため、明示的なインポート文は冗長になります。 -
ParseSocketControlMessage
関数内の構造体初期化の簡潔化:src/pkg/syscall/sockcmsg_unix.go
のParseSocketControlMessage
関数内で、SocketControlMessage
構造体の初期化方法が変更されました。変更前:
m := SocketControlMessage{} m.Header = *h m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)] cmsgs = append(cmsgs, m)
変更後:
m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]} msgs = append(msgs, m)
これは、Goの構造体リテラルを使用して、構造体のフィールドを一度に初期化する、より簡潔な方法です。これにより、コードの行数が減り、
m
がどのように構築されるかがより明確になります。また、エラー変数名もe
からerr
に変更され、Goの標準的なエラー変数名に統一されています。
これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のベストプラクティスとスタイルガイドに沿ってコードベースを改善するためのものです。
コアとなるコードの変更箇所
src/pkg/syscall/sockcmsg_linux.go
--- a/src/pkg/syscall/sockcmsg_linux.go
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -6,33 +6,31 @@
package syscall
-import (
- "unsafe"
-)
+import "unsafe"
// UnixCredentials encodes credentials into a socket control message
// for sending to another process. This can be used for
// authentication.
func UnixCredentials(ucred *Ucred) []byte {
-- buf := make([]byte, CmsgSpace(SizeofUcred))
-- cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
-- cmsg.Level = SOL_SOCKET
-- cmsg.Type = SCM_CREDENTIALS
-- cmsg.SetLen(CmsgLen(SizeofUcred))
-- *((*Ucred)(cmsgData(cmsg))) = *ucred
-- return buf
-+ b := make([]byte, CmsgSpace(SizeofUcred))
-+ h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-+ h.Level = SOL_SOCKET
-+ h.Type = SCM_CREDENTIALS
-+ h.SetLen(CmsgLen(SizeofUcred))
-+ *((*Ucred)(cmsgData(h))) = *ucred
-+ return b
}
// ParseUnixCredentials decodes a socket control message that contains
// credentials in a Ucred structure. To receive such a message, the
// SO_PASSCRED option must be enabled on the socket.
-func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, error) {
-- if msg.Header.Level != SOL_SOCKET {
-+func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
-+ if m.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
-- if msg.Header.Type != SCM_CREDENTIALS {
-+ if m.Header.Type != SCM_CREDENTIALS {
return nil, EINVAL
}
-- ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
-+ ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
return &ucred, nil
}
src/pkg/syscall/sockcmsg_unix.go
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -8,9 +8,7 @@
package syscall
-import (
- "unsafe"
-)
+import "unsafe"
// Round the length of a raw sockaddr up to align it propery.
func cmsgAlignOf(salen int) int {
@@ -38,77 +36,69 @@ func CmsgSpace(datalen int) int {
return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
}
-func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
-- return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
-+func cmsgData(h *Cmsghdr) unsafe.Pointer {
-+ return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
}
-// SocketControlMessage represents a socket control message.
type SocketControlMessage struct {
Header Cmsghdr
Data []byte
}
-func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
-- var (
-- h *Cmsghdr
-- dbuf []byte
-- e error
-- cmsgs []SocketControlMessage
-- )
--
-- for len(buf) >= CmsgLen(0) {
-- h, dbuf, e = socketControlMessageHeaderAndData(buf)
-- if e != nil {
-- break
-- }
-- m := SocketControlMessage{}
-- m.Header = *h
-- m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
-- cmsgs = append(cmsgs, m)
-- buf = buf[cmsgAlignOf(int(h.Len)):]
-+func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
-+ var msgs []SocketControlMessage
-+ for len(b) >= CmsgLen(0) {
-+ h, dbuf, err := socketControlMessageHeaderAndData(b)
-+ if err != nil {
-+ return nil, err
-+ }
-+ m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]}
-+ msgs = append(msgs, m)
-+ b = b[cmsgAlignOf(int(h.Len)):]
}
--
-- return cmsgs, e
-+ return msgs, nil
}
-func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
-- h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
-- if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
-+func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
-+ h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-+ if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
return nil, nil, EINVAL
}
-- return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
-+ return h, b[cmsgAlignOf(SizeofCmsghdr):], nil
}
// UnixRights encodes a set of open file descriptors into a socket
// control message for sending to another process.
func UnixRights(fds ...int) []byte {
datalen := len(fds) * 4
-- buf := make([]byte, CmsgSpace(datalen))
-- cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
-- cmsg.Level = SOL_SOCKET
-- cmsg.Type = SCM_RIGHTS
-- cmsg.SetLen(CmsgLen(datalen))
--
-- data := uintptr(cmsgData(cmsg))
-+ b := make([]byte, CmsgSpace(datalen))
-+ h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-+ h.Level = SOL_SOCKET
-+ h.Type = SCM_RIGHTS
-+ h.SetLen(CmsgLen(datalen))
-+ data := uintptr(cmsgData(h))
for _, fd := range fds {
*(*int32)(unsafe.Pointer(data)) = int32(fd)
data += 4
}
--
-- return buf
-+ return b
}
// ParseUnixRights decodes a socket control message that contains an
// integer array of open file descriptors from another process.
-func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
-- if msg.Header.Level != SOL_SOCKET {
-+func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
-+ if m.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
-- if msg.Header.Type != SCM_RIGHTS {
-+ if m.Header.Type != SCM_RIGHTS {
return nil, EINVAL
}
-- fds := make([]int, len(msg.Data)>>2)
-- for i, j := 0, 0; i < len(msg.Data); i += 4 {
-- fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
-+ fds := make([]int, len(m.Data)>>2)
-+ for i, j := 0, 0; i < len(m.Data); i += 4 {
-+ fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
j++
}
return fds, nil
コアとなるコードの解説
src/pkg/syscall/sockcmsg_linux.go
UnixCredentials
関数:- 変更前:
buf
とcmsg
という変数名を使用していました。 - 変更後:
b
とh
という短い変数名に変更されました。機能的な変更はありません。buf
はバイトスライス、cmsg
はCmsghdr
ポインタを指すため、それぞれb
とh
に短縮されています。
- 変更前:
ParseUnixCredentials
関数:- 変更前: 引数
msg
を使用していました。 - 変更後: 引数
m
という短い変数名に変更されました。関数内部でのmsg.Header.Level
やmsg.Data
へのアクセスもm.Header.Level
やm.Data
に変更されています。機能的な変更はありません。
- 変更前: 引数
src/pkg/syscall/sockcmsg_unix.go
import "unsafe"
の削除:- ファイル冒頭の
import ("unsafe")
が削除されました。これは、Goのコンパイラがコード内でunsafe
パッケージの機能(例:unsafe.Pointer
)が使用されていることを検出すると、自動的にインポートするため、明示的なインポート文が不要になったためです。
- ファイル冒頭の
cmsgData
関数:- 変更前: 引数
cmsg
を使用していました。 - 変更後: 引数
h
という短い変数名に変更されました。機能的な変更はありません。
- 変更前: 引数
ParseSocketControlMessage
関数:- 変更前: 引数
buf
、内部変数h
,dbuf
,e
,cmsgs
を使用していました。SocketControlMessage
の初期化は複数行に分かれていました。 - 変更後: 引数
b
、内部変数h
,dbuf
,err
,msgs
という短い変数名に変更されました。特にエラー変数e
がGoの慣習であるerr
に変更されています。 - 最も顕著な変更は、
SocketControlMessage
構造体の初期化が、m := SocketControlMessage{Header: *h, Data: ...}
という単一行の構造体リテラルに簡潔化された点です。これにより、コードの可読性が向上し、意図がより明確になります。
- 変更前: 引数
socketControlMessageHeaderAndData
関数:- 変更前: 引数
buf
を使用していました。 - 変更後: 引数
b
という短い変数名に変更されました。機能的な変更はありません。
- 変更前: 引数
UnixRights
関数:- 変更前:
buf
とcmsg
という変数名を使用していました。 - 変更後:
b
とh
という短い変数名に変更されました。機能的な変更はありません。
- 変更前:
ParseUnixRights
関数:- 変更前: 引数
msg
を使用していました。 - 変更後: 引数
m
という短い変数名に変更されました。機能的な変更はありません。
- 変更前: 引数
これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のコーディングスタイルとイディオムに沿ってコードをより簡潔で読みやすいものにするためのものです。
関連リンク
- Go言語
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - Linux
sendmsg(2)
man page (ソケットコントロールメッセージに関する詳細): https://man7.org/linux/man-pages/man2/sendmsg.2.html - Linux
cmsg(3)
man page (コントロールメッセージの構造に関する詳細): https://man7.org/linux/man-pages/man3/cmsg.3.html - Go言語のコードレビューガイドライン (変数名の慣習など): https://go.dev/doc/effective_go#names
参考にした情報源リンク
- Go言語の公式ドキュメント
- Linux man pages (sendmsg, cmsg)
- Go言語のコーディングスタイルに関する一般的な情報源
- Gerrit Change-ID:
https://golang.org/cl/7016044
(これはGoプロジェクトのコードレビューシステムへのリンクであり、コミットの詳細な議論や変更の経緯を確認できます。)