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

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

このコミットは、Go言語の標準ライブラリであるstrconvパッケージとfmtパッケージにおける、文字列のクォート(引用符付け)に関する挙動の明確化を目的としています。具体的には、strconv.CanBackquote関数のレポート内容と、fmtパッケージの書式指定子%#qの動作説明が修正されています。

コミット

commit 4692711d7f172ab69a9576ffbe753314755f780a
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Feb 26 06:33:59 2013 +0800

    strconv, fmt: clarify behavior of CanBackquote and "%#q".
    Fixes #4858.
    
    R=golang-dev, bradfitz, r, rsc
    CC=golang-dev
    https://golang.org/cl/7387044

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

https://github.com/golang/go/commit/4692711d7f172ab69a9576ffbe753314755f780a

元コミット内容

このコミットの元のメッセージは以下の通りです。

strconv, fmt: clarify behavior of CanBackquote and "%#q".
Fixes #4858.

これは、strconvパッケージとfmtパッケージにおいて、CanBackquote関数と%#q書式指定子の挙動を明確にすることを目的としていることを示しています。また、GoのIssue #4858を修正するものであることも明記されています。

変更の背景

このコミットは、Go言語のIssue #4858「fmt: %#q should use backquotes if possible」を修正するために行われました。このIssueでは、fmtパッケージの%#q書式指定子が、文字列をバッククォート( `)で囲んで出力する際に、どのような条件でバッククォートを使用するのかが不明確であるという問題が提起されていました。

具体的には、%#qはGoの文字列リテラル形式で値をクォートしますが、バッククォート文字列リテラル(raw string literal)はエスケープシーケンスを解釈しないため、特定の文字(特にバッククォート自身や制御文字)が含まれる場合には使用できません。しかし、既存のドキュメントではその条件が明確に記述されていませんでした。

また、strconv.CanBackquote関数も、ある文字列がバッククォートで囲まれたGoの文字列リテラルとして有効であるかどうかを報告する関数ですが、その「有効」の定義が曖昧でした。特に、制御文字や改行を含む文字列に対する挙動がユーザーにとって直感的ではない可能性がありました。

このコミットは、これらの曖昧さを解消し、開発者がCanBackquote%#qの挙動をより正確に理解できるようにするために導入されました。

前提知識の解説

このコミットの理解には、以下のGo言語の概念に関する知識が必要です。

  • Goの文字列リテラル: Goには主に2種類の文字列リテラルがあります。
    • 解釈済み文字列リテラル (Interpreted string literal): ダブルクォート(")で囲まれた文字列で、バックスラッシュ(\)によるエスケープシーケンス(例: \n\t\")が解釈されます。
    • 生文字列リテラル (Raw string literal): バッククォート( `)で囲まれた文字列で、エスケープシーケンスは解釈されず、バッククォート内の文字がそのまま文字列の内容となります。ただし、バッククォート自身は生文字列リテラル内に含めることはできません。また、改行を含むことができます。
  • fmtパッケージ: Go言語のフォーマットI/Oを扱うパッケージです。fmt.Printfなどの関数を使って、様々な型の値を指定された書式で文字列に変換して出力します。
    • 書式指定子: fmtパッケージでは、%v(デフォルト)、%s(文字列)、%q(クォートされた文字列)など、様々な書式指定子が提供されています。
    • フラグ: 書式指定子には、追加の挙動を制御するためのフラグを付加できます。例えば、#フラグは「代替形式」を意味し、型に応じた特別な書式を適用します。%#qの場合、可能な場合はバッククォートで囲まれた文字列として出力しようとします。
  • strconvパッケージ: 文字列と基本的なデータ型(数値、真偽値など)との間の変換を扱うパッケージです。
    • strconv.CanBackquote関数: この関数は、与えられた文字列がバッククォートで囲まれたGoの文字列リテラルとして表現可能かどうかを判定します。

技術的詳細

このコミットは、fmtパッケージのドキュメントとstrconv.CanBackquote関数の実装およびドキュメントの両方を修正することで、挙動の明確化を図っています。

fmtパッケージのドキュメント修正 (src/pkg/fmt/doc.go)

変更前は、%#qのドキュメントが「print a raw (backquoted) string if possible for %q (%#q);」と記述されていました。これは「可能であれば生(バッククォートで囲まれた)文字列を出力する」という意味ですが、「可能」の具体的な条件が不明確でした。

変更後は、「for %q, print a raw (backquoted) string if strconv.CanBackquote returns true;」と修正されました。これにより、%#qがバッククォート文字列を使用する条件が、strconv.CanBackquote関数の戻り値に依存することが明確に示されました。これは、fmtパッケージの挙動がstrconvパッケージの定義に準拠することを意味し、一貫性が向上します。

strconv.CanBackquote関数のドキュメント修正 (src/pkg/strconv/quote.go)

変更前は、CanBackquote関数のドキュメントが「CanBackquote returns whether the string s would be a valid Go string literal if enclosed in backquotes.」と記述されていました。これも「有効なGo文字列リテラル」の定義が曖昧でした。

変更後は、「CanBackquote reports whether the string s can be represented unchanged as a single-line backquoted string without control characters other than space and tab.」と修正されました。この新しいドキュメントは、CanBackquoteが以下の条件を満たす場合にtrueを返すことを明確にしています。

  1. 変更なしで表現可能: 文字列の内容がそのままバッククォート内に収まること。
  2. 単一行: 文字列が改行を含まないこと。
  3. 特定の制御文字以外を含まない: スペース( )とタブ(\t)以外の制御文字(ASCII値が (32) 未満の文字)を含まないこと。
  4. バッククォート文字を含まない: 文字列自身がバッククォート( `)を含まないこと。

この修正により、CanBackquoteの挙動がより厳密に定義され、特に制御文字や改行を含む文字列に対する期待される結果が明確になりました。これにより、開発者はCanBackquoteの戻り値に基づいて、文字列をバッククォートで安全に表現できるかどうかを判断できるようになります。

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

src/pkg/fmt/doc.go

--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -74,7 +74,8 @@
 		-	pad with spaces on the right rather than the left (left-justify the field)
 		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
 			0X for hex (%#X); suppress 0x for %p (%#p);
-			print a raw (backquoted) string if possible for %q (%#q);
+			for %q, print a raw (backquoted) string if strconv.CanBackquote
+			returns true;
 			write e.g. U+0078 'x' if the character is printable for %U (%#U).
 		' '	(space) leave a space for elided sign in numbers (% d);
 			put spaces between bytes printing strings or slices in hex (% x, % X)

src/pkg/strconv/quote.go

--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -139,8 +139,9 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
 	return append(dst, QuoteRuneToASCII(r)...)
 }
 
-// CanBackquote returns whether the string s would be
-// a valid Go string literal if enclosed in backquotes.
+// CanBackquote reports whether the string s can be represented
+// unchanged as a single-line backquoted string without control
+// characters other than space and tab.
 func CanBackquote(s string) bool {
 	for i := 0; i < len(s); i++ {
 		if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {

コアとなるコードの解説

src/pkg/fmt/doc.go の変更

この変更は、fmtパッケージのドキュメンテーションコメント内の%#q書式指定子の説明を更新しています。

  • 変更前: print a raw (backquoted) string if possible for %q (%#q);
    • 「可能であれば生(バッククォートで囲まれた)文字列を出力する」という記述で、「可能」の条件が不明確でした。
  • 変更後: for %q, print a raw (backquoted) string if strconv.CanBackquote returns true;
    • strconv.CanBackquotetrueを返す場合、生(バッククォートで囲まれた)文字列を出力する」と明確に記述されました。これにより、%#qの挙動がstrconv.CanBackquoteの定義に直接リンクされ、一貫性と明確性が向上しました。

src/pkg/strconv/quote.go の変更

この変更は、strconv.CanBackquote関数のドキュメンテーションコメントを更新しています。関数の実際のロジック(ループ内の条件 (s[i] < ' ' && s[i] != '\t') || s[i] == ''`)は変更されていませんが、そのロジックが何を意図しているのかをより正確に説明しています。

  • 変更前: CanBackquote returns whether the string s would be a valid Go string literal if enclosed in backquotes.
    • 「文字列sがバッククォートで囲まれた場合に有効なGo文字列リテラルになるかどうかを返す」という記述で、「有効」の定義が曖昧でした。
  • 変更後: CanBackquote reports whether the string s can be represented unchanged as a single-line backquoted string without control characters other than space and tab.
    • 「文字列sが、スペースとタブ以外の制御文字を含まず、単一行のバッククォート文字列として変更なしで表現できるかどうかを報告する」と明確に記述されました。
    • この新しい説明は、以下の条件を暗に示しています。
      • s[i] < ' ' && s[i] != '\t': スペース(ASCII 32)より小さい文字(制御文字)で、かつタブ(ASCII 9)ではない文字が含まれていないこと。これは、改行文字(\n)も含まれないことを意味し、結果として「単一行」の条件を満たします。
      • s[i] == ''`: バッククォート文字自身が含まれていないこと。
    • これにより、CanBackquotetrueを返す具体的な条件がユーザーにとって非常に明確になりました。

これらの変更は、Go言語のドキュメントの正確性と、関連するパッケージ間の挙動の一貫性を高める上で重要な役割を果たしています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント(fmtパッケージ、strconvパッケージ)
  • Go言語のソースコード(src/pkg/fmt/doc.go, src/pkg/strconv/quote.go
  • Go言語のIssueトラッカー(Issue #4858)
  • Go言語のコードレビューシステム(CL 7387044)
  • Go言語の文字列リテラルに関する一般的な情報源