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

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

このコミットは、Go言語のチュートリアルに含まれるサーバーコードのクリーンアップを目的としています。具体的には、チュートリアル内のサンプルコードにおける型名の命名規則をGo言語の慣習に合わせる変更が行われています。これにより、コードの可読性とGo言語のイディオムへの準拠が向上しています。

コミット

commit 96777ea2a756bcb0f31946e4f1bfa375d5505830
Author: Rob Pike <r@golang.org>
Date:   Fri Jan 30 10:18:58 2009 -0800

    clean up server code in tutorial
    
    R=rsc
    DELTA=15  (1 added, 0 deleted, 14 changed)
    OCL=23889
    CL=23889

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

https://github.com/golang/go/commit/96777ea2a756bcb0f31946e4f1bfa375d5505830

元コミット内容

clean up server code in tutorial
R=rsc
DELTA=15  (1 added, 0 deleted, 14 changed)
OCL=23889
CL=23889

変更の背景

このコミットの主な背景は、Go言語のチュートリアルコードの品質と一貫性を向上させることです。特に、Go言語では識別子(変数、関数、型など)の最初の文字が大文字か小文字かによって、その識別子がエクスポートされる(パッケージ外からアクセス可能になる)か、アンエクスポートされる(パッケージ内でのみアクセス可能になる)かが決まるという重要な命名規則があります。

元のコードでは、Requestという型名が大文字で始まっていましたが、これは通常、パッケージ外に公開されるべき型に用いられる命名です。しかし、チュートリアル内のこのRequest型は、そのコンテキストにおいてパッケージ内部でのみ使用されることを意図している可能性が高いです。同様に、BinOpも同様の理由で変更されています。

このコミットは、Go言語のイディオムと命名規則に沿って、内部的に使用される型名を小文字で始めるrequestおよびbinOpに変更することで、コードの意図をより明確にし、Go言語のベストプラクティスに準拠させることを目的としています。これにより、チュートリアルを読む学習者がGo言語の正しい命名規則を理解しやすくなります。

また、doc/progs/runファイルにおけるserverの実行に関するコメント変更も行われています。以前は「server hangs; don't run it」とありましたが、変更後は「server hangs; don't run it, just compile it」となり、さらに6g server.goというコンパイルコマンドが追加されています。これは、チュートリアルのサーバーコードが完全な実行可能なアプリケーションとして設計されているわけではなく、概念を説明するためのものであるため、実行ではなくコンパイルのみを推奨する意図があると考えられます。

前提知識の解説

Go言語の命名規則(エクスポートとアンエクスポート)

Go言語には、識別子(変数、関数、型、定数など)の可視性を制御するための独特かつシンプルな命名規則があります。

  • エクスポートされた識別子 (Exported Identifiers): 識別子の名前が大文字で始まる場合、その識別子はパッケージ外からアクセス可能です。これは、他のパッケージから利用できるAPIの一部として公開されることを意味します。例えば、MyStructDoSomethingなど。
  • アンエクスポートされた識別子 (Unexported Identifiers): 識別子の名前が小文字で始まる場合、その識別子は定義されたパッケージ内でのみアクセス可能です。これは、パッケージの内部実装の詳細であり、外部からは直接利用できないことを意味します。例えば、myFieldcalculateInternalなど。

この規則は、Go言語におけるモジュール性(カプセル化)の基本的なメカニズムであり、APIの設計において非常に重要です。外部に公開すべきでない内部的な型や関数は小文字で始めることで、意図しない外部からのアクセスを防ぎ、パッケージのインターフェースを明確に保ちます。

Go言語の並行処理(GoroutineとChannel)

このコミットで変更されているコードは、Go言語の並行処理の主要な概念であるgoroutinechannelを使用しています。

  • Goroutine: Go言語における軽量なスレッドのようなものです。goキーワードを関数呼び出しの前に置くことで、その関数を新しいgoroutineとして並行して実行できます。非常に低コストで生成でき、数千、数万のgoroutineを同時に実行することが可能です。
  • Channel: goroutine間でデータを安全にやり取りするための通信メカニズムです。チャネルは、goroutine間の同期と通信を可能にし、共有メモリによる競合状態(race condition)を防ぐのに役立ちます。チャネルは型付けされており、特定の型の値のみを送受信できます。

チュートリアルのサーバーコードは、goroutineを使ってリクエスト処理を並行化し、channelを使ってリクエストとレスポンスをやり取りするパターンを示しています。

技術的詳細

このコミットの技術的な変更は、主にGo言語の命名規則への準拠と、それに伴うコードの整合性の維持にあります。

  1. 型名の変更:

    • Request型がrequest型にリネームされました。
    • BinOp型がbinOp型にリネームされました。 この変更は、これらの型がパッケージ内部でのみ使用されることを意図しているため、Go言語の命名規則に従い、アンエクスポートされた(小文字で始まる)名前に変更されたものです。
  2. 変数名の変更:

    • request型のインスタンスを参照する変数名が、requestからreqに変更されました。これは、型名と変数名が同じになることを避けるための一般的なGoの慣習です。reqrequestの短縮形としてよく使われます。
  3. 関数シグネチャの変更:

    • runserverstartServerといった関数が、引数や戻り値の型として*Request*BinOpを使用していた箇所が、それぞれ*request*binOpに変更されました。これは、型名のリネームに伴う必然的な変更であり、コード全体の整合性を保つために必要です。
  4. チュートリアルテキストの修正:

    • doc/go_tutorial.txt内の説明文で、"Request" typeという記述が"request" typeに修正されました。これは、コードの変更に合わせてチュートリアルの説明も更新されたことを示しています。
  5. doc/progs/runの変更:

    • serverプログラムの実行に関するコメントが変更され、コンパイルのみを推奨するようになりました。
    • 6g server.goというコンパイルコマンドが追加されました。6gはGoの初期のコンパイラ名であり、当時のGo環境におけるコンパイル方法を示しています。

これらの変更は、機能的な振る舞いを変更するものではなく、コードのスタイルとGo言語のイディオムへの準拠を改善するためのものです。これにより、チュートリアルコードがより「Goらしい」ものとなり、学習者にとっての模範となることを意図しています。

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

doc/go_tutorial.txt

--- a/doc/go_tutorial.txt
+++ b/doc/go_tutorial.txt
@@ -755,7 +755,7 @@ With channels, it's possible to serve multiple independent client goroutines wit
 writing an actual multiplexer.  The trick is to send the server a channel in the message,
 which it will then use to reply to the original sender.
 A realistic client-server program is a lot of code, so here is a very simple substitute
-to illustrate the idea.  It starts by defining a "Request" type, which embeds a channel
+to illustrate the idea.  It starts by defining a "request" type, which embeds a channel
 that will be used for the reply.
 
 --PROG progs/server.go /type.request/ /^}/

doc/progs/run

--- a/doc/progs/run
+++ b/doc/progs/run
@@ -68,7 +68,8 @@ testit print_string "" "77 Sunset Strip"
 testitpipe sieve "sed 10q" "2 3 5 7 11 13 17 19 23 29"
 testitpipe sieve "sed 10q" "2 3 5 7 11 13 17 19 23 29"
 
-# server hangs; don't run it
+# server hangs; don't run it, just compile it
+6g server.go
 testit server1 "" ""
 
 rm -f 6.out *.6

doc/progs/server.go

--- a/doc/progs/server.go
+++ b/doc/progs/server.go
@@ -11,21 +11,21 @@ type request struct {
 
 type binOp (a, b int) int;
 
-func run(op *BinOp, request *Request) {
-	result := op(request.a, request.b);
-	request.replyc <- result;
+func run(op *binOp, req *request) {
+	result := op(req.a, req.b);
+	req.replyc <- result;
 }
 
-func server(op *BinOp, service chan *Request) {
+func server(op *binOp, service chan *request) {
 	for {
-		request := <-service;
-		go run(op, request);  // don't wait for it
+		req := <-service;
+		go run(op, req);  // don't wait for it
 	}
 }
 
-func startServer(op *BinOp) chan *Request {
-	req := make(chan *Request);
-	go Server(op, req);
+func startServer(op *binOp) chan *request {
+	req := make(chan *request);
+	go server(op, req);
 	return req;
 }

doc/progs/server1.go

--- a/doc/progs/server1.go
+++ b/doc/progs/server1.go
@@ -11,9 +11,9 @@ type request struct {
 
 type binOp (a, b int) int;
 
-func run(op *binOp, request *request) {
-	result := op(request.a, request.b);
-	request.replyc <- result;
+func run(op *binOp, req *request) {
+	result := op(req.a, req.b);
+	req.replyc <- result;
 }
 
 func server(op *binOp, service chan *request, quit chan bool) {

コアとなるコードの解説

このコミットで変更されたGoコードは、Go言語の並行処理モデル(goroutineとchannel)を用いたシンプルなサーバーの例です。

  • type request struct { ... }:

    • これはクライアントからのリクエストを表す構造体です。abは演算のオペランド、replycはサーバーが結果をクライアントに送り返すためのチャネルです。
    • 元のコードではRequestと大文字で始まっていましたが、このコミットでrequestと小文字に変更されました。これにより、この型がパッケージ内部でのみ使用されることを明確に示しています。
  • type binOp (a, b int) int;:

    • これは二項演算を表す関数型です。abという2つの整数を引数にとり、整数を返します。
    • 元のコードではBinOpと大文字で始まっていましたが、このコミットでbinOpと小文字に変更されました。これもrequest型と同様に、内部使用を意図した変更です。
  • func run(op *binOp, req *request):

    • この関数は、与えられた二項演算opをリクエストreqのオペランドabに適用し、その結果をリクエストのreplycチャネルに送信します。
    • 引数の型が*BinOpから*binOpに、*Requestから*requestに変更され、変数名もrequestからreqに変更されました。
  • func server(op *binOp, service chan *request):

    • この関数はサーバーのメインループです。serviceチャネルからリクエストを受け取り、新しいgoroutineでrun関数を呼び出してリクエストを処理します。go run(op, req)とすることで、各リクエストが並行して処理され、サーバーが次のリクエストをすぐに受け付けられるようになります。
    • 引数の型が*BinOpから*binOpに、chan *Requestからchan *requestに変更され、変数名もrequestからreqに変更されました。
  • func startServer(op *binOp) chan *request:

    • この関数はサーバーを起動し、クライアントがリクエストを送信するためのチャネルを返します。新しいgoroutineでserver関数を起動します。
    • 引数の型が*BinOpから*binOpに、戻り値の型がchan *Requestからchan *requestに変更されました。また、go Server(op, req)go server(op, req)に変更され、関数名の先頭が大文字から小文字に修正されています。これは、server関数自体もパッケージ内部でのみ使用されることを意図しているため、Goの命名規則に合わせた変更です。

これらの変更は、Go言語の命名規則に厳密に従うことで、コードの意図(内部使用か外部公開か)を明確にし、Go言語のイディオムに沿ったコードスタイルを維持することを目的としています。

関連リンク

特になし。

参考にした情報源リンク