[インデックス 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プロジェクトのコードレビューシステム