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

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

このコミットは、Go言語の標準ライブラリ encoding/xml パッケージ内の ExampleUnmarshal 関数のテストコードにおける匿名フィールドのアンマーシャリング例を修正するものです。既存の例が匿名フィールドの挙動を正確に示していなかったため、より適切で理解しやすいように変更されました。

コミット

  • コミットハッシュ: 490c3d4a426b197283bf3a02bedd84654a268f28
  • 作者: Gustavo Niemeyer gustavo@niemeyer.net
  • 日付: Fri Feb 24 14:45:32 2012 -0500
  • コミットメッセージ:
    encoding/xml: fix anonymous field Unmarshal example
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5697043
    

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

https://github.com/golang/go/commit/490c3d4a426b197283bf3a02bedd84654a268f28

元コミット内容

encoding/xml: fix anonymous field Unmarshal example

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

変更の背景

Go言語の encoding/xml パッケージは、XMLデータをGoの構造体(struct)にアンマーシャリング(デシリアライズ)する機能を提供します。この際、Goの構造体には「匿名フィールド(anonymous field)」という特徴的な機能があり、これは別の構造体をフィールド名なしで埋め込むことができるものです。匿名フィールドのフィールドは、あたかも親構造体の直下のフィールドであるかのようにアクセスできます。

encoding/xmlUnmarshal 関数は、この匿名フィールドを適切に処理するように設計されています。しかし、既存の ExampleUnmarshal のテストコードは、匿名フィールド Address の初期化方法や、XMLデータ内の要素の扱いに関して、その挙動を正確に反映していませんでした。特に、XML内の <address> 要素が無視されるというコメントがありましたが、これは匿名フィールドの挙動とは直接関係なく、またXML構造も匿名フィールドのアンマーシャリングを明確に示すものではありませんでした。

このコミットの目的は、ExampleUnmarshal の例を修正し、encoding/xml.Unmarshal が匿名フィールドをどのように処理するかをより正確かつ明確にデモンストレーションすることです。これにより、開発者が匿名フィールドを含むXMLアンマーシャリングの挙動を正しく理解できるようになります。

前提知識の解説

Go言語の構造体と匿名フィールド

Go言語の構造体は、異なる型のフィールドをまとめるための複合データ型です。匿名フィールドは、構造体内にフィールド名なしで別の型(通常は別の構造体)を埋め込む機能です。これにより、埋め込まれた型のメソッドやフィールドが、あたかも外側の構造体のメンバーであるかのように直接アクセスできるようになります。これは、継承に似た「コンポジション(合成)」を実現するGoのイディオムです。

例:

type Address struct {
    Street string
    City   string
}

type Person struct {
    Name string
    Address // 匿名フィールド
}

func main() {
    p := Person{Name: "Alice"}
    p.City = "New York" // AddressのCityフィールドに直接アクセス
}

encoding/xml パッケージと Unmarshal 関数

encoding/xml パッケージは、XMLドキュメントとGoの構造体の間でデータを変換するための機能を提供します。

  • xml.Unmarshal(data []byte, v interface{}) error: この関数は、XMLデータ(バイトスライス)をGoのインターフェース v が指す構造体にデコード(アンマーシャリング)します。Unmarshal は、XML要素名と構造体のフィールド名をマッチングさせ、XML属性や要素のテキストコンテンツを対応するフィールドに割り当てます。
  • XMLタグ: 構造体のフィールドには、xml:"element_name" のような構造体タグ(struct tag)を付けることで、XML要素名とのマッピングを明示的に指定できます。タグがない場合、フィールド名がそのままXML要素名として扱われます。
  • 匿名フィールドのアンマーシャリング: encoding/xml は、匿名フィールドを特別に扱います。XMLデータが匿名フィールドの型に対応する要素を持っている場合、その要素の内容は匿名フィールドにアンマーシャリングされます。また、匿名フィールドの内部のフィールドが、親構造体のフィールドであるかのようにXML要素と直接マッピングされることもあります。

技術的詳細

このコミットの技術的詳細は、encoding/xml.Unmarshal が匿名フィールドをどのように処理するか、そしてその挙動を例で正確に表現することにあります。

元の ExampleUnmarshal では、Result 構造体に Address という匿名フィールドが埋め込まれていました。

type Result struct {
    Name  string
    Phone string
    Groups []string `xml:"Group>Value"`
    Address // 匿名フィールド
}

そして、XMLデータには <Address> 要素が含まれていました。

<Address>123 Main Street</Address>

しかし、Goの Address 構造体は CityState フィールドを持っており、XMLの <Address> 要素が単一のテキストコンテンツ("123 Main Street")を持つ場合、encoding/xml はこれを Address 構造体の CityState フィールドに直接マッピングすることはできません。これは、XMLの構造とGoの構造体のマッピングが一致しないためです。

また、元のコードでは v.Address = Address{"Hanga Roa", "Easter Island"} のように、アンマーシャリング前に匿名フィールド Address を初期化していました。これは、アンマーシャリングの動作を不明瞭にする可能性がありました。Unmarshal は通常、既存のフィールド値を上書きするか、XMLデータに存在しない場合はそのままにするため、初期化がアンマーシャリングの結果にどう影響するかを誤解させる恐れがありました。

今回の修正では、XMLデータ内の <Address> 要素を削除し、代わりに Address 構造体のフィールドである CityState に直接対応する <City><State> 要素をXMLに追加しました。

<City>Hanga Roa</City>
<State>Easter Island</State>

これにより、Unmarshal は匿名フィールド Address の内部にある CityState フィールドに、XMLの対応する要素から値を正しくアンマーシャリングできるようになります。これは、匿名フィールドのフィールドが、親構造体のフィールドであるかのようにXML要素と直接マッピングされるという encoding/xml の挙動を明確に示しています。

また、v.Address = Address{"Hanga Roa", "Easter Island"} の行を削除することで、アンマーシャリングがどのように構造体のフィールドを埋めるかをより純粋にデモンストレーションしています。

さらに、XMLデータに <Company>Example Inc.</Company> という新しい要素が追加され、これに対応する構造体フィールドがないため、この要素が Unmarshal によって無視されることを示すコメントが追加されました。これは、XMLデータに存在するがGoの構造体に対応するフィールドがない要素がどのように扱われるかを示す良い例となります。

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

diff --git a/src/pkg/encoding/xml/example_test.go b/src/pkg/encoding/xml/example_test.go
index 082ce6803d..97c8c0b0dc 100644
--- a/src/pkg/encoding/xml/example_test.go
+++ b/src/pkg/encoding/xml/example_test.go
@@ -52,7 +52,7 @@ func ExampleMarshalIndent() {
 
 // This example demonstrates unmarshaling an XML excerpt into a value with
 // some preset fields. Note that the Phone field isn't modified and that
-// the XML <address> element is ignored. Also, the Groups field is assigned
+// the XML <Company> element is ignored. Also, the Groups field is assigned
 // considering the element path provided in its tag.
 func ExampleUnmarshal() {
 	type Email struct {
@@ -71,11 +71,11 @@ func ExampleUnmarshal() {
 		Address
 	}
 	v := Result{Name: "none", Phone: "none"}
-	v.Address = Address{"Hanga Roa", "Easter Island"}
 
 	data := `
 		<Person>
 			<FullName>Grace R. Emlin</FullName>
+			<Company>Example Inc.</Company>
 			<Email where="home">
 				<Addr>gre@example.com</Addr>
 			</Email>
@@ -86,7 +86,8 @@ func ExampleUnmarshal() {
 				<Value>Friends</Value>
 				<Value>Squash</Value>
 			</Group>
-			<Address>123 Main Street</Address>
+			<City>Hanga Roa</City>
+			<State>Easter Island</State>
 		</Person>
 	`
 	err := xml.Unmarshal([]byte(data), &v)

コアとなるコードの解説

このコミットでは、src/pkg/encoding/xml/example_test.go ファイルの ExampleUnmarshal 関数が変更されています。

  1. コメントの修正:

    - // the XML <address> element is ignored. Also, the Groups field is assigned
    + // the XML <Company> element is ignored. Also, the Groups field is assigned
    

    元のコメントでは「XML <address> 要素が無視される」とありましたが、これは匿名フィールドのアンマーシャリングの挙動を正確に反映していませんでした。修正後、XMLデータに新しく追加される <Company> 要素が構造体に対応するフィールドを持たないため、これが無視されることを示すようにコメントが変更されました。これにより、Unmarshal が未知の要素をどのように扱うかという別の側面も例示されています。

  2. 匿名フィールド Address の初期化の削除:

    - v.Address = Address{"Hanga Roa", "Easter Island"}
    

    アンマーシャリング前に v.Address を初期化する行が削除されました。これにより、Unmarshal 関数がXMLデータから直接 Address 構造体のフィールドを埋める挙動がより明確になります。初期化が残っていると、XMLからの値が既存の値を上書きするのか、それとも初期値がそのまま残るのかが不明瞭になる可能性がありました。

  3. XMLデータの変更:

    +			<Company>Example Inc.</Company>
    ...
    -			<Address>123 Main Street</Address>
    +			<City>Hanga Roa</City>
    +			<State>Easter Island</State>
    
    • <Company>Example Inc.</Company> が追加されました。これは、Goの Result 構造体に対応するフィールドがないため、Unmarshal によって無視される要素の例として機能します。
    • 元の <Address>123 Main Street</Address> が削除され、代わりに <City>Hanga Roa</City><State>Easter Island</State> が追加されました。これは、Result 構造体に匿名で埋め込まれた Address 構造体の CityState フィールドに、XMLデータから直接値がアンマーシャリングされることを明確に示しています。encoding/xml は、匿名フィールドの内部のフィールドを、親構造体のフィールドであるかのように扱ってマッピングします。この変更により、匿名フィールドのアンマーシャリングの意図がより正確に伝わるようになりました。

これらの変更により、ExampleUnmarshalencoding/xml.Unmarshal が匿名フィールドをどのように処理し、また対応するフィールドがないXML要素をどのように無視するかを、より正確かつ教育的にデモンストレーションするようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の匿名フィールドに関する解説記事やドキュメント(Web検索結果より)
  • encoding/xml パッケージの公式ドキュメントとソースコード
  • Go言語の構造体とXMLアンマーシャリングに関する一般的な知識