[インデックス 14591] ファイルの概要
本コミットは、Go言語の標準ライブラリである net/rpc
パッケージにおける Register
メソッドのドキュメントを更新し、その動作(標準エラーへのログ出力)を明確にするとともに、付属のコード例における誤った参照(&
)を修正するものです。これにより、net/rpc
の利用者が Register
メソッドの挙動をより正確に理解し、また提供されるコード例が正しく動作するようになります。
コミット
commit 91527eb1d7e3054e660692638a526340d19d14b5
Author: Russ Cox <rsc@golang.org>
Date: Mon Dec 10 01:42:53 2012 -0500
net/rpc: document that Register logs to standard error
Also fix spurious & in example.
Fixes #4349.
Fixes #4489.
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/6905058
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/91527eb1d7e3054e660692638a526340d19d14b5
元コミット内容
net/rpc
: Register
が標準エラーにログを出力することをドキュメント化。
また、例の中の余分な &
を修正。
Fixes #4349. Fixes #4489.
変更の背景
このコミットは、Go言語の net/rpc
パッケージにおける2つの既存の問題(Issue #4349 と #4489)に対処するために行われました。
-
Issue #4349:
net/rpc
のRegister
メソッドが、サービス登録に失敗した場合にエラーを標準エラー(log
パッケージのデフォルト出力先)に出力するという、ドキュメント化されていない挙動を持っていました。この挙動は、特にサーバーアプリケーションがバックグラウンドで動作している場合や、ログの収集・解析を行っている場合に予期せぬ出力となり、混乱を招く可能性がありました。このコミットは、この重要な動作を明示的にドキュメントに追加することで、開発者がRegister
メソッドの副作用を正確に理解し、適切に処理できるようにすることを目的としています。 -
Issue #4489:
net/rpc
パッケージのドキュメントに含まれるコード例に、client.Go
メソッドの呼び出しで誤ってポインタ演算子&
が使用されている箇所がありました。具体的には、quotient
という変数が既にポインタ型 (*Quotient
) であるにもかかわらず、さらに"ient
と記述されており、これはコンパイルエラーを引き起こすか、少なくとも誤解を招く記述でした。このコミットは、この「余分な&
」を削除し、コード例が正しく、かつGoのイディオムに沿ったものになるように修正します。
これらの修正は、net/rpc
パッケージの使いやすさと信頼性を向上させ、開発者がよりスムーズにRPCサービスを構築・利用できるようにするために重要です。
前提知識の解説
Go言語の net/rpc
パッケージ
net/rpc
パッケージは、Go言語でRPC(Remote Procedure Call)サービスを簡単に構築するための標準ライブラリです。RPCは、異なるアドレス空間にあるプログラムが、あたかもローカルな手続きであるかのように、リモートのプロシージャ(関数やメソッド)を呼び出すことを可能にする技術です。
net/rpc
の主な特徴は以下の通りです。
- サービス登録:
rpc.Register
またはrpc.RegisterName
メソッドを使用して、Goの構造体(レシーバ)のメソッドをRPCサービスとして公開します。これらのメソッドは、特定のシグネチャ(引数と戻り値の型)を持つ必要があります。 - クライアントとサーバー: サーバー側は
rpc.Accept
やhttp.HandleRPC
などでリクエストを受け付け、クライアント側はrpc.Dial
などでサーバーに接続し、Client.Call
やClient.Go
でリモートメソッドを呼び出します。 - エンコーディング: デフォルトではGoの
gob
エンコーディングを使用しますが、jsonrpc
など他のエンコーディングもサポートされています。
Go言語の log
パッケージと標準エラー
Go言語の log
パッケージは、シンプルなロギング機能を提供します。デフォルトでは、log
パッケージの出力は標準エラー出力(os.Stderr
)に送られます。これは、プログラムの通常の出力(標準出力 os.Stdout
)とは別に、エラーメッセージや診断情報を出力するための一般的なUNIXの慣習です。
log.Printf
や log.Println
などの関数を使用すると、メッセージがデフォルトのロガーによって標準エラーに出力されます。log.SetOutput
関数を使用することで、出力先をファイルや他の io.Writer
に変更することも可能です。
Go言語のポインタと参照渡し
Go言語では、変数のアドレスを指す「ポインタ」を使用できます。ポインタは *
記号で型を宣言し、&
記号で変数のアドレスを取得します。
var p *int
:p
はint
型の値を指すポインタです。x := 10
:x
はint
型の変数です。p = &x
:p
はx
のアドレスを保持します。*p
:p
が指す値(この場合はx
の値)にアクセスします。
関数やメソッドに引数を渡す際、値そのものを渡す「値渡し」と、値のアドレス(ポインタ)を渡す「参照渡し」があります。参照渡しを行うと、関数内で引数の値を変更した場合、呼び出し元の変数の値も変更されます。
net/rpc
の Client.Go
メソッドは、結果を格納するための引数としてポインタを期待します。例えば、client.Go("Method", args, &reply, nil)
のように、reply
変数のアドレスを渡すことで、リモートメソッドの実行結果が reply
に書き込まれます。
技術的詳細
net/rpc.Server.Register
メソッドのログ出力
net/rpc
パッケージの Server.Register
メソッドは、RPCサービスとして公開するレシーバ(Goの構造体のインスタンス)を登録するために使用されます。このメソッドは、レシーバがRPCの規約(エクスポートされた型であること、適切なシグネチャを持つメソッドを持つことなど)を満たしているかを検証します。
本コミット以前は、Register
メソッドがこれらの検証に失敗した場合、エラーを log
パッケージを通じて標準エラーに出力するという挙動がドキュメントに明記されていませんでした。これは、log
パッケージがデフォルトで標準エラーに出力するため、開発者が意図しないログ出力に遭遇する可能性がありました。
今回の修正では、src/pkg/net/rpc/server.go
の Register
メソッドのコメントに以下の記述が追加されました。
// It also logs the error using package log.
この変更により、Register
メソッドがエラーを返すだけでなく、内部的に log
パッケージを使用して標準エラーにエラーメッセージを出力するという、その「副作用」が明確にドキュメント化されました。これにより、開発者は Register
の呼び出し元でエラーを処理するだけでなく、標準エラー出力も監視する必要があることを認識できます。これは、特にデバッグや運用監視の際に重要な情報となります。
client.Go
のコード例の修正
net/rpc
パッケージのドキュメントには、非同期RPC呼び出しを行う Client.Go
メソッドの使用例が含まれています。Client.Go
は、リモートメソッド名、引数、結果を格納するポインタ、および Done
チャネルに送信される Call
構造体へのポインタを引数に取ります。
元のコード例では、quotient
という変数が既に *Quotient
型(Quotient
構造体へのポインタ)として宣言されているにもかかわらず、client.Go("Arith.Divide", args, "ient, nil)
のように "ient
と記述されていました。これは、ポインタのポインタを渡そうとするものであり、Goの型システムにおいては誤りです。quotient
自体が既にポインタであるため、そのアドレスをさらに取る必要はありません。
今回の修正では、この「余分な &
」が削除され、正しい記述である client.Go("Arith.Divide", args, quotient, nil)
に変更されました。これにより、コード例はGoのポインタの扱いに沿ったものとなり、そのままコピー&ペーストして使用しても正しく動作するようになります。
コアとなるコードの変更箇所
--- a/src/pkg/net/rpc/server.go
+++ b/src/pkg/net/rpc/server.go
@@ -112,7 +112,7 @@
// Asynchronous call
quotient := new(Quotient)
- divCall := client.Go("Arith.Divide", args, "ient, nil)
+ divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall := <-divCall.Done // will be equal to divCall
// check errors, print, etc.
@@ -219,8 +219,8 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
// - exported method
// - two arguments, both pointers to exported structs
// - one return value, of type error
-// It returns an error if the receiver is not an exported type or has no
-// suitable methods.
+// It returns an error if the receiver is not an exported type or has
+// no methods or unsuitable methods. It also logs the error using package log.
// The client accesses each method using a string of the form "Type.Method",
// where Type is the receiver\'s concrete type.
func (server *Server) Register(rcvr interface{}) error {
コアとなるコードの解説
1. client.Go
の呼び出し例の修正
- divCall := client.Go("Arith.Divide", args, "ient, nil)
+ divCall := client.Go("Arith.Divide", args, quotient, nil)
この変更は、src/pkg/net/rpc/server.go
内のコメントブロックにあるコード例の一部です。
元のコードでは "ient
となっていましたが、quotient
変数は既に new(Quotient)
によって *Quotient
型(Quotient
構造体へのポインタ)として初期化されています。Client.Go
メソッドの第3引数(reply
)は、リモート呼び出しの結果を格納するためのポインタを期待します。quotient
自体が既にポインタであるため、そのアドレスをさらに取る &
は不要であり、誤りでした。
修正後の quotient
は、Quotient
型の新しいインスタンスへのポインタを直接 Client.Go
に渡しており、これが正しいGoのイディオムであり、net/rpc
のAPIの期待する形式です。
2. Server.Register
メソッドのドキュメント更新
-// It returns an error if the receiver is not an exported type or has no
-// suitable methods.
+// It returns an error if the receiver is not an exported type or has
+// no methods or unsuitable methods. It also logs the error using package log.
この変更は、Server.Register
メソッドのGoDocコメントに対するものです。
元のコメントでは、Register
メソッドがレシーバの型やメソッドがRPCの規約に適合しない場合にエラーを返すことが述べられていました。
修正後のコメントでは、その説明に加えて、It also logs the error using package log.
という一文が追加されました。これは、Register
メソッドが内部的に log
パッケージを使用して、登録失敗時のエラーメッセージを標準エラーに出力するという、これまでドキュメント化されていなかった重要な挙動を明示するものです。
このドキュメントの追加により、開発者は Register
メソッドがエラーを返すだけでなく、ログ出力という副作用も持つことを明確に理解できるようになり、デバッグやエラーハンドリングの際に役立ちます。
関連リンク
- Issue #4349:
net/rpc
: document that Register logs to standard error - Issue #4489:
net/rpc
: spurious & in example - Gerrit Change-Id:
https://golang.org/cl/6905058
(Goプロジェクトのコードレビューシステムへのリンク)
参考にした情報源リンク
- Go言語公式ドキュメント:
net/rpc
パッケージ - Go言語公式ドキュメント:
log
パッケージ - Go言語のポインタに関する解説(一般的なGoのチュートリアルやドキュメント)
- https://go.dev/tour/moretypes/1 (Go Tour: Pointers)
- https://go.dev/doc/effective_go#pointers_vs_values (Effective Go: Pointers vs. Values)
- GitHub Issues: Go言語リポジトリのIssueトラッカー
- Gerrit Code Review: Goプロジェクトのコードレビューシステム