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

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

このコミットは、Go言語の公式ドキュメントである doc/effective_go.html に、ラベル付き break および continue ステートメントに関する議論を追加するものです。これにより、Go言語におけるこれらの制御構造の利用方法と、それがどのような状況で役立つのかが明確に説明されます。

コミット

commit 2a5dcfafec11744d55692838912901c58ba43bd2
Author: Rob Pike <r@golang.org>
Date:   Tue Sep 17 07:41:45 2013 +1000

    effective_go: add a discussion of labeled break and continue
    Fixes #5725.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/13705044

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

https://github.com/golang/go/commit/2a5dcfafec11744d55692838912901c58ba43bd2

元コミット内容

    effective_go: add a discussion of labeled break and continue
    Fixes #5725.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/13705044

変更の背景

この変更は、Go言語の effective_go ドキュメントに、ラベル付き break および continue ステートメントに関する説明を追加することを目的としています。これは、Go言語の制御構造に関する既存の記述を補完し、特にネストされたループや switch ステートメントからの脱出、または特定のループの継続といった、より複雑な制御フローのシナリオにおける breakcontinue の強力な機能について、開発者がより深く理解できるようにするためのものです。

コミットメッセージにある Fixes #5725 は、この変更がGoのIssueトラッカーで報告された問題 #5725 を解決することを示しています。このIssueは、おそらく effective_go ドキュメントにおけるラベル付き break および continue の説明の不足、または不明瞭さに関するものであったと推測されます。Rob Pike氏(Go言語の共同設計者の一人)によるこのコミットは、Go言語のベストプラクティスとイディオムをまとめた effective_go の品質と網羅性を向上させるための継続的な取り組みの一環です。

前提知識の解説

effective_go とは

effective_go は、Go言語の公式ドキュメントの一部であり、Go言語を効果的に記述するためのヒントやイディオム、ベストプラクティスをまとめたものです。Go言語の基本的な構文や機能を知っている開発者が、よりGoらしい(idiomatic Go)コードを書くための指針を提供します。Go言語の設計思想や哲学が反映されており、Go開発者にとっては必読のドキュメントとされています。

break ステートメント

break ステートメントは、最も内側の forswitch、または select ステートメントの実行を即座に終了するために使用されます。break が実行されると、制御は終了したステートメントの直後のステートメントに移ります。

例:

for i := 0; i < 10; i++ {
    if i == 5 {
        break // iが5になったらループを終了
    }
    fmt.Println(i)
}
// 出力: 0 1 2 3 4

continue ステートメント

continue ステートメントは、最も内側の for ループの現在のイテレーションをスキップし、次のイテレーションに進むために使用されます。continue が実行されると、ループの条件式が再評価され、次のイテレーションが開始されます。

例:

for i := 0; i < 10; i++ {
    if i%2 == 0 {
        continue // iが偶数なら次のイテレーションへ
    }
    fmt.Println(i)
}
// 出力: 1 3 5 7 9

ラベル付きステートメント

Go言語では、forswitchselect ステートメントにラベルを付けることができます。ラベルは識別子であり、コロン (:) でステートメントの前に置かれます。このラベルは、breakcontinue ステートメントのターゲットとして使用され、ネストされた制御構造から特定の外側のステートメントを終了したり、特定のループの次のイテレーションに進んだりすることを可能にします。

例:

OuterLoop:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            if i == 1 && j == 1 {
                break OuterLoop // OuterLoop全体を終了
            }
            fmt.Printf("i: %d, j: %d\n", i, j)
        }
    }
// 出力:
// i: 0, j: 0
// i: 0, j: 1
// i: 0, j: 2
// i: 1, j: 0

技術的詳細

このコミットは、effective_go ドキュメントにラベル付き breakcontinue の使用法に関する具体的な説明とコード例を追加することで、Go言語の制御フローの理解を深めます。

Go言語における breakcontinue は、C言語やJavaなどの他のCライクな言語と同様に機能しますが、Goでは goto ステートメントの使用が推奨されない代わりに、ラベル付き breakcontinue が特定の制御フローシナリオで代替手段として提供されます。

ラベル付き break の詳細

break ステートメントは、通常、最も内側の forswitch、または select ステートメントを終了します。しかし、ネストされたループや switch ステートメントから、より外側の特定のステートメントを終了したい場合、ラベル付き break が非常に役立ちます。

ドキュメントに追加された説明では、switch ステートメント内で break を使用して switch を早期に終了できること、そして、より外側のループを終了するためにラベル付き break を使用できることが強調されています。これは、特にエラー条件が発生した場合に、複数のネストされた層を一度に抜け出す必要がある場合に有効です。

追加されたコード例は、この概念を具体的に示しています。

Loop:
	for n := 0; n < len(src); n += size {
		case src[n] < sizeOne:
			if validateOnly {
				break // このbreakはswitchを終了
			}
			size = 1
			update(src[n])

		case src[n] < sizeTwo:
			if n+1 >= len(src) {
				err = errShortInput
				break Loop // このbreakは外側のLoopを終了
			}
			if validateOnly {
				break // このbreakはswitchを終了
			}
			size = 2
			update(src[n] + src[n+1]<<shift)
		}
	}

この例では、Loop: というラベルが for ループに付けられています。

  • break (ラベルなし) は、その switch ステートメントを終了します。
  • break Loop は、Loop とラベル付けされた外側の for ループ全体を終了します。これは、errShortInput のような致命的なエラーが発生した場合に、処理を完全に停止するために使用されます。

ラベル付き continue の詳細

continue ステートメントもまた、オプションでラベルを受け入れますが、これは for ループにのみ適用されます。ラベル付き continue は、指定されたラベルを持つ for ループの現在のイテレーションをスキップし、そのループの次のイテレーションに進みます。これは、ネストされたループにおいて、内側のループから直接外側の特定のループの次のイテレーションに進みたい場合に有用です。

ドキュメントでは、「continue ステートメントもオプションのラベルを受け入れますが、それはループにのみ適用されます」と簡潔に述べられています。これは、continueswitchselect には適用されないという break との重要な違いを強調しています。

goto との比較

Go言語では goto ステートメントも存在しますが、その使用は一般的に推奨されません。goto はコードの可読性を損ない、複雑な制御フローを生み出す可能性があるためです。ラベル付き breakcontinue は、goto が提供する一部の機能(特定のポイントへのジャンプ)を、より構造化された方法で実現するための代替手段として機能します。これにより、コードの構造を保ちつつ、特定の制御フローのニーズを満たすことができます。

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

変更は doc/effective_go.html ファイルに対して行われました。具体的には、以下の部分が追加・修正されています。

--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -506,6 +506,8 @@ slightly generalized
 <code>switch</code> is more flexible;
 <code>if</code> and <code>switch</code> accept an optional
 initialization statement like that of <code>for</code>;
+<code>break</code> and <code>continue</code> statements
+take an optional label to identify what to break or continue;
 and there are new control structures including a type switch and a
 multiway communications multiplexer, <code>select</code>.
 The syntax is also slightly different:
@@ -781,7 +783,46 @@ func shouldEscape(c byte) bool {
 </pre>
 
 <p>
-Here\'s a comparison routine for byte slices that uses two
+Although they are not nearly as common in Go as some other C-like
+languages, <code>break</code> statements can be used to terminate
+a <code>switch</code> early.
+Sometimes, though, it\'s necessary to break out of a surrounding loop,
+not the switch, and in Go that can be accomplished by putting a label
+on the loop and "breaking" to that label.
+This example shows both uses.
+</p>
+
+<pre>
+Loop:
+\tfor n := 0; n < len(src); n += size {
+\t\tcase src[n] < sizeOne:
+\t\t\tif validateOnly {
+\t\t\t\tbreak
+\t\t\t}\n\t\t\tsize = 1
+\t\t\tupdate(src[n])
+
+\t\tcase src[n] < sizeTwo:
+\t\t\tif n+1 >= len(src) {
+\t\t\t\terr = errShortInput
+\t\t\t\tbreak Loop
+\t\t\t}
+\t\t\tif validateOnly {
+\t\t\t\tbreak
+\t\t\t}
+\t\t\tsize = 2
+\t\t\tupdate(src[n] + src[n+1]<<shift)
+\t\t}
+\t}
+</pre>
+
+<p>
+Of course, the <code>continue</code> statement also accepts an optional label
+but it applies only to loops.
+</p>
+
+<p>
+To close this section, here\'s a comparison routine for byte slices that uses two
 <code>switch</code> statements:
 </p>
 <pre>

コアとなるコードの解説

このコミットは、effective_go.html の2つの主要なセクションに影響を与えています。

  1. 制御構造の概要部分 (@ -506,6 +506,8): 既存の制御構造の概要に、breakcontinue ステートメントがオプションでラベルを受け入れるという記述が追加されました。これは、Go言語の制御フロー機能の包括的なリストを更新し、読者がこれらの機能の存在を早期に認識できるようにするためです。

    +<code>break</code> and <code>continue</code> statements
    +take an optional label to identify what to break or continue;
    
  2. breakcontinue の詳細な説明部分 (@ -781,7 +783,46): このセクションは、ラベル付き breakcontinue の具体的な使用例と説明で大幅に拡張されました。

    • ラベル付き break の説明: 「Goでは他のCライクな言語ほど一般的ではないが、break ステートメントは switch を早期に終了するために使用できる」という導入から始まります。 次に、「しかし、switch ではなく、囲んでいるループから抜け出す必要がある場合があり、Goではループにラベルを付けてそのラベルに「break」することでそれが可能になる」と説明されています。 そして、両方の使用法を示す具体的なコード例が提供されています。

      <p>
      Although they are not nearly as common in Go as some other C-like
      languages, <code>break</code> statements can be used to terminate
      a <code>switch</code> early.
      Sometimes, though, it's necessary to break out of a surrounding loop,
      not the switch, and in Go that can be accomplished by putting a label
      on the loop and "breaking" to that label.
      This example shows both uses.
      </p>
      
      <pre>
      Loop:
      	for n := 0; n < len(src); n += size {
      		case src[n] < sizeOne:
      			if validateOnly {
      				break
      			}
      			size = 1
      			update(src[n])
      
      		case src[n] < sizeTwo:
      			if n+1 >= len(src) {
      				err = errShortInput
      				break Loop
      			}
      			if validateOnly {
      				break
      			}
      			size = 2
      			update(src[n] + src[n+1]<<shift)
      		}
      	}
      </pre>
      

      このコード例は、Loop: というラベルが付けられた for ループ内で switch ステートメントを使用するシナリオを示しています。

      • break (ラベルなし) は、その switch ケースを終了し、switch ステートメントの直後のコードに制御を移します。
      • break Loop は、Loop とラベル付けされた外側の for ループ全体を終了します。これは、errShortInput のようなエラーが発生した場合に、ネストされた構造から完全に抜け出すために使用されます。
    • ラベル付き continue の説明: 「もちろん、continue ステートメントもオプションのラベルを受け入れますが、それはループにのみ適用されます」という簡潔な説明が追加されています。これは、continueswitchselect には適用されないという重要な制約を明確にしています。

      <p>
      Of course, the <code>continue</code> statement also accepts an optional label
      but it applies only to loops.
      </p>
      

これらの変更により、effective_go ドキュメントは、Go言語のラベル付き break および continue ステートメントの機能と適切な使用法について、より詳細で実践的なガイダンスを提供するようになりました。これにより、開発者はより複雑な制御フローを効果的に管理し、より堅牢で読みやすいGoコードを作成できるようになります。

関連リンク

参考にした情報源リンク