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

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

このコミットは、Go言語の標準ライブラリである text/template パッケージのドキュメントに対する軽微な編集と、text/template/parse パッケージのドキュメントの明確化を目的としています。主な変更点は、テンプレートの使用例の追加、関数値フィールドの動作に関する説明の改善、そして parse パッケージの役割の明確化です。

コミット

commit 68b35b0852eaa90fb61ac4b28c0a3700efc7f762
Author: Rob Pike <r@golang.org>
Date:   Sun Feb 19 07:45:12 2012 +1100

    templates: minor edits to the documentation
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5677084

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

https://github.com/golang/go/commit/68b35b0852eaa90fb61ac4b28c0a3700efc7f762

元コミット内容

templates: minor edits to the documentation

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5677084

変更の背景

Go言語の text/template パッケージは、テキストベースの出力を生成するための強力なテンプレートエンジンを提供します。このパッケージは、ウェブアプリケーションのHTML生成、設定ファイルの動的生成、コード生成など、多岐にわたる用途で利用されます。

このコミットが行われた2012年2月時点では、Go言語はまだ比較的新しい言語であり、標準ライブラリのドキュメントは継続的に改善されていました。特に、ユーザーがパッケージをより効果的に利用できるように、具体的な使用例や複雑な機能の明確な説明が求められていました。

このコミットの背景には、以下の点が挙げられます。

  1. 入門者への配慮: text/template パッケージは非常に柔軟である反面、その機能の多さから初めて利用するユーザーにとっては学習曲線が存在します。簡単な例を追加することで、パッケージの基本的な使い方を迅速に理解できるようにすることが目的です。
  2. 機能の明確化: テンプレート内で利用できる「アクション」の中でも、特に「関数値フィールド」の振る舞いは、メソッドとの違いなど、誤解を招きやすい部分でした。このコミットでは、その動作をより正確に説明し、ユーザーが意図した通りにテンプレートを記述できるように改善しています。
  3. 内部パッケージの役割の明確化: text/template/parse パッケージは、text/templatehtml/template の内部で利用されるパーサーの機能を提供します。しかし、そのドキュメントが不明瞭だと、ユーザーが誤って直接このパッケージを利用しようとする可能性があります。このコミットは、parse パッケージが一般ユーザー向けではないことを明確にし、適切な利用方法を促しています。
  4. テンプレートの再利用性の説明: Parse メソッドの呼び出しに関する説明を補足し、テンプレートを複数の場所で利用する際の CloneAddParseTree メソッドの重要性を強調することで、より効率的なテンプレート管理を促しています。

これらの変更は、text/template パッケージの使いやすさと理解度を向上させ、Go言語コミュニティ全体の生産性向上に貢献することを目的としています。

前提知識の解説

このコミットの変更内容を理解するためには、以下のGo言語および text/template パッケージに関する基本的な知識が必要です。

  1. Go言語の基本:

    • パッケージ (Package): Go言語のコードはパッケージにまとめられます。text/templatetext/template/parse は標準ライブラリのパッケージです。
    • 構造体 (Struct): 関連するデータをまとめるための型です。例として、Inventory 構造体が登場します。
    • メソッド (Method): 構造体に関連付けられた関数です。レシーバー(. の前のインスタンス)を介して呼び出されます。
    • 関数 (Function): 特定の処理を実行するコードブロックです。
    • エラーハンドリング: Go言語では、関数が複数の戻り値を返すことができ、慣習として最後に戻り値として error 型を返します。エラーが発生した場合は nil ではないエラー値が返され、呼び出し元でそのエラーを処理します。
  2. Goの text/template パッケージ:

    • テンプレート (Template): テキストと、Goのデータ構造から値を埋め込むための「アクション」を組み合わせたものです。
    • アクション (Actions): テンプレート内で {{...}} の形式で記述される特殊な構文です。データの表示、条件分岐、繰り返し処理などを行います。
    • データコンテキスト (Data Context): テンプレートが実行される際に提供されるGoのデータ(構造体、マップ、スライスなど)です。テンプレート内のアクションは、このデータコンテキストにアクセスして値を抽出します。
    • ドット (.): テンプレート内で現在のデータコンテキストを参照するために使用されます。例えば、.Field は現在のデータコンテキストの Field という名前のフィールドにアクセスします。
    • パイプライン (Pipelines): テンプレート内で複数のアクションを連結し、前の結果を次の入力として渡すメカニズムです。
    • 関数値フィールド (Function-valued fields): 構造体のフィールドが関数型である場合、そのフィールドをテンプレート内で呼び出すことができます。これはメソッドと似ていますが、レシーバーを渡さない点が異なります。
    • template.New(name string): 新しいテンプレートを作成します。
    • template.Parse(text string): テンプレート文字列を解析し、テンプレートオブジェクトを構築します。
    • template.Execute(wr io.Writer, data interface{}): テンプレートをデータコンテキストで実行し、結果を指定された io.Writer に書き込みます。
    • template.Clone() / template.AddParseTree(): 既存のテンプレートから新しいテンプレートを作成したり、解析済みのツリーを追加したりするためのメソッドです。これにより、テンプレートの再利用や組み合わせが可能になります。
  3. text/template/parse パッケージ:

    • このパッケージは、text/templatehtml/template パッケージが内部的に使用する、テンプレート文字列を解析して抽象構文木(AST: Abstract Syntax Tree)を構築するための機能を提供します。通常、アプリケーション開発者が直接このパッケージを使用することはありません。

これらの知識を前提として、コミットの変更内容を詳細に見ていきます。

技術的詳細

このコミットは、主に src/pkg/text/template/doc.gosrc/pkg/text/template/parse/parse.go の2つのファイルに影響を与えています。

src/pkg/text/template/doc.go の変更点

このファイルは text/template パッケージの公式ドキュメント(go doc text/template で表示される内容)を定義しています。

  1. 簡単な使用例の追加:

    • Inventory という構造体を定義し、そのフィールド (Material, Count) をテンプレートで利用する具体的なコード例が追加されました。
    • この例は、「17 items are made of wool」という出力結果を示すことで、テンプレートの基本的なデータバインディングと実行フローを明確に示しています。
    • これにより、初めて text/template を使う開発者が、すぐに動くコードを試せるようになりました。
    // 追加されたコード例
    Here is a trivial example that prints "17 items are made of wool".
    
    	type Inventory struct {
    		Material string
    		Count    uint
    	}
    	sweaters := Inventory{"wool", 17}
    	tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
    	if err != nil { panic(err) }
    	err = tmpl.Execute(os.Stdout, sweaters)
    	if err != nil { panic(err) }
    
    More intricate examples appear below.
    
  2. 関数値フィールドの動作に関する説明の改善:

    • テンプレートのアクションリストにおいて、「niladic function-valued struct field」(引数を取らない関数値構造体フィールド)に関する説明が追加されました。
    • これは、template.Funcs で登録する関数とは異なり、データコンテキスト(構造体)のフィールドが関数である場合に、その関数をテンプレート内で呼び出す方法を説明しています。
    • 重要な点は、「Methods (of structs) but do not pass a receiver.」(構造体のメソッドのように振る舞うが、レシーバーを渡さない)という明確な記述が追加されたことです。これにより、メソッドとの違いが明確になりました。
    // 追加された説明
    	- The name of a niladic function-valued struct field of the data,
    	  preceded by a period, such as
    		.Function
    	  Function-valued fields behave like methods (of structs) but do not
    	  pass a receiver.
    
  3. 関数値フィールドのアクション構文の追加:

    • テンプレートのアクション構文のリストに、 .Function [Argument...] という新しい形式が追加されました。
    • これは、引数を取る関数値フィールドをテンプレート内で呼び出す際の構文を示しています。
    • ここでも、「A function-valued field of a struct works like a method but does not pass the receiver.」(構造体の関数値フィールドはメソッドのように機能するが、レシーバーを渡さない)という補足が繰り返され、この概念の重要性が強調されています。
    // 追加されたアクション構文
    	.Function [Argument...]
    		A function-valued field of a struct works like a method but does
    		not pass the receiver.
    
  4. Parse メソッドとテンプレートのコピーに関する説明の更新:

    • Parse メソッドが複数回呼び出される場合のテンプレートの扱いについて、説明が更新されました。
    • 以前は「template definition must be parsed multiple times to create distinct *Template values.」とだけ書かれていましたが、これに加えて「or must be copied with the Clone or AddParseTree method.」という選択肢が追加されました。
    • これは、既存のテンプレートを再利用しつつ、異なる関連付けを持つ新しいテンプレートを作成する際に、CloneAddParseTree メソッドがより効率的な方法であることを示唆しています。
    --- a/src/pkg/text/template/doc.go
    +++ b/src/pkg/text/template/doc.go
    @@ -303,7 +325,7 @@ produce the text
     By construction, a template may reside in only one association. If it's
     necessary to have a template addressable from multiple associations, the
     template definition must be parsed multiple times to create distinct *Template
    -values.
    +values, or must be copied with the Clone or AddParseTree method.
    

src/pkg/text/template/parse/parse.go の変更点

このファイルは text/template/parse パッケージのドキュメントを定義しています。

  1. パッケージドキュメントの明確化:

    • パッケージのコメントが更新され、parse パッケージが text/template および html/template のために解析ツリーを構築するものであることが明確にされました。
    • 最も重要な変更は、「Clients should use those packages to construct templates rather than this one, which provides shared internal data structures not intended for general use.」(クライアントは、一般用途を意図しない共有内部データ構造を提供するこのパッケージではなく、それらのパッケージ(text/templatehtml/template)を使用してテンプレートを構築すべきである)という文言が追加されたことです。
    • これにより、parse パッケージが内部的なものであり、直接利用すべきではないという意図が明確に伝わるようになりました。
    --- a/src/pkg/text/template/parse/parse.go
    +++ b/src/pkg/text/template/parse/parse.go
    @@ -2,8 +2,10 @@
     // Use of this source code is governed by a BSD-style
     // license that can be found in the LICENSE file.\n
    -// Package parse builds parse trees for templates.  The grammar is defined
    -// in the documents for the template package.
    +// Package parse builds parse trees for templates as defined by text/template
    +// and html/template. Clients should use those packages to construct templates
    +// rather than this one, which provides shared internal data structures not
    +// intended for general use.
     package parse
    

これらの変更は、Go言語のドキュメントの品質向上に対する継続的な取り組みの一環であり、ユーザーがライブラリをより正確かつ効率的に利用できるようにするための重要な改善です。

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

このコミットにおける「コアとなるコードの変更箇所」は、厳密には機能的なコードの変更ではなく、ドキュメンテーションの変更です。しかし、これらのドキュメンテーションの変更は、text/template パッケージの利用方法や内部構造に関する理解を深める上で非常に重要です。

変更されたファイルは以下の2つです。

  1. src/pkg/text/template/doc.go:

    • このファイルは、text/template パッケージのトップレベルのドキュメントを定義しています。Goのドキュメンテーションツール (go doc) がこのファイルの内容を読み取り、ユーザーに表示します。
    • 追加されたコード例、関数値フィールドの動作説明、および Parse メソッドに関する補足説明がここに含まれます。
  2. src/pkg/text/template/parse/parse.go:

    • このファイルは、text/template/parse パッケージのトップレベルのドキュメントを定義しています。
    • parse パッケージが内部的な用途であることを明確にするためのコメントがここに追加されました。

これらの変更は、Go言語のドキュメンテーション慣習に従い、doc.go ファイルにパッケージ全体の概要や使用例を記述し、各Goファイルの先頭コメントにそのファイルが属するパッケージの目的を記述するという原則に基づいています。

コアとなるコードの解説

前述の通り、このコミットは機能的なコードの変更ではなく、ドキュメンテーションの変更が中心です。しかし、そのドキュメンテーションがGoのコードの一部として扱われるため、「コアとなるコードの解説」として、変更されたドキュメンテーションの内容を詳細に解説します。

src/pkg/text/template/doc.go の解説

このファイルは、text/template パッケージのユーザー向けドキュメントのソースです。

  1. テンプレート使用例の追加:

    Here is a trivial example that prints "17 items are made of wool".
    
    	type Inventory struct {
    		Material string
    		Count    uint
    	}
    	sweaters := Inventory{"wool", 17}
    	tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
    	if err != nil { panic(err) }
    	err = tmpl.Execute(os.Stdout, sweaters)
    	if err != nil { panic(err) }
    

    このコードスニペットは、text/template の最も基本的な使い方を示しています。

    • Inventory 構造体は、テンプレートに渡されるデータの型を定義します。
    • template.New("test") で新しいテンプレートインスタンスを作成します。"test" はテンプレートの名前です。
    • .Parse("...") でテンプレート文字列を解析します。{{.Count}}{{.Material}} は、それぞれ sweaters 構造体の Count フィールドと Material フィールドの値を埋め込むためのアクションです。
    • tmpl.Execute(os.Stdout, sweaters) でテンプレートを実行します。os.Stdout は出力先(標準出力)を指定し、sweaters はテンプレートに渡すデータコンテキストです。
    • if err != nil { panic(err) } はGo言語の典型的なエラーハンドリングパターンです。
  2. 関数値フィールドの説明の追加:

    	- The name of a niladic function-valued struct field of the data,
    	  preceded by a period, such as
    		.Function
    	  Function-valued fields behave like methods (of structs) but do not
    	  pass a receiver.
    

    この部分は、構造体のフィールドが関数である場合のテンプレート内での呼び出し方について説明しています。

    • niladic は「引数を取らない」という意味です。
    • .Function のように、ドット (.) の後にフィールド名を続けることで、その関数フィールドを呼び出すことができます。
    • 重要なのは、「メソッドのように振る舞うが、レシーバーを渡さない」という点です。通常のメソッド呼び出しでは、obj.Method() のように obj がレシーバーとしてメソッドに渡されますが、関数値フィールドの呼び出しでは、そのフィールドが保持する関数が直接呼び出され、レシーバーは渡されません。
  3. 関数値フィールドのアクション構文の追加:

    	.Function [Argument...]
    		A function-valued field of a struct works like a method but does
    		not pass the receiver.
    

    これは、引数を取る関数値フィールドの呼び出し構文です。

    • [Argument...] は、関数に渡す引数を指定できることを示します。
    • ここでも、レシーバーが渡されないという点が強調されています。
  4. Parse とテンプレートのコピーに関する説明の更新:

    --- a/src/pkg/text/template/doc.go
    +++ b/src/pkg/text/template/doc.go
    @@ -303,7 +325,7 @@ produce the text
     By construction, a template may reside in only one association. If it's
     necessary to have a template addressable from multiple associations, the
     template definition must be parsed multiple times to create distinct *Template
    -values.
    +values, or must be copied with the Clone or AddParseTree method.
    

    この変更は、テンプレートの再利用に関する重要なガイダンスを提供します。

    • 以前は、同じテンプレート定義を複数の場所で使いたい場合、毎回 Parse を呼び出して新しい *Template 値を作成する必要がある、とされていました。
    • しかし、Clone または AddParseTree メソッドを使用することで、既存の解析済みテンプレートツリーを効率的にコピーし、新しい *Template 値を作成できることが追記されました。これは、パフォーマンスの観点からも、コードの簡潔さの観点からも推奨される方法です。

src/pkg/text/template/parse/parse.go の解説

このファイルは、text/template/parse パッケージのドキュメントのソースです。

--- a/src/pkg/text/template/parse/parse.go
+++ b/src/pkg/text/template/parse/parse.go
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.\n
-// Package parse builds parse trees for templates.  The grammar is defined
-// in the documents for the template package.
+// Package parse builds parse trees for templates as defined by text/template
+// and html/template. Clients should use those packages to construct templates
+// rather than this one, which provides shared internal data structures not
+// intended for general use.
 package parse

この変更は、parse パッケージの役割を明確にし、誤用を防ぐためのものです。

  • 元のコメントは、「parse パッケージはテンプレートの解析ツリーを構築する」とだけ述べていました。
  • 新しいコメントでは、text/templatehtml/template の両方のために解析ツリーを構築すること、そして最も重要な点として、「クライアント(つまり、このパッケージを利用する開発者)は、一般用途を意図しない共有内部データ構造を提供するこのパッケージではなく、text/templatehtml/template を使用してテンプレートを構築すべきである」と明記されています。
  • これは、parse パッケージがGoの内部実装の詳細であり、直接触れるべきではないことを強く示唆しています。これにより、開発者が不必要に低レベルのAPIに依存することを防ぎ、より安定した上位レベルのAPI (text/templatehtml/template) の利用を促します。

これらのドキュメンテーションの変更は、Go言語のライブラリ設計における「使いやすさ」と「明確さ」を重視する哲学を反映しています。

関連リンク

参考にした情報源リンク