はじめに
こんにちは!!!!ライクル事業部エンジニアの黒田(@knkurokuro7)です。
今日もGoについてブログを書こうと思います!
背景
Goには「書式指定子」というものがあります。
fmt.Printf("僕は、%s", "Gopher")
などの%s
のように、フォーマットを指定する際に使います。
よく目にするものとしては、文字列型に対応する%s、整数型に対応する%d、error型に対応する%wなどがあります。
最近、業務で以下のようなコードを見かけました。
u, err := url.Parse(r.Image.URL) if err != nil { return nil, fmt.Errorf("画像URLの形式が正しくありません: %q : %w", r.Image.URL, err) }
ここで、 r.Image.URLは文字列型なので、「あれ、%sでもいいのではないか」と思いました。 また%qをこの時に初めて見たので、調べてみることにしました。
%qについて
まず前提として、%qについて調べてみました。
以下のfmtパッケージの公式ドキュメントに書式指定子の仕様について詳しく書かれています。
%qについての説明は、IntegerとString and slice of bytesのセクションに書かれています。
Integer
%q a single-quoted character literal safely escaped with Go syntax.
String and slice of bytes
%q a double-quoted string safely escaped with Go syntax
またこういう説明もありました。
When formatting a single integer code point or a rune string (type rune) with %q, invalid Unicode code points are changed to the Unicode replacement character, U+FFFD, as in strconv.QuoteRune.
まとめると、
- 整数型の場合は、Goシンタックスで安全にエスケープされたシングルクォートで囲まれた文字列リテラルにフォーマットする。
- 文字列型もしくはスライス型の場合は、Goシンタックスで安全にエスケープされたダブルクォートで囲まれた文字列にフォーマットする。
- 単一の整数コードポイントまたはルーン文字列(rune 型)の場合は、無効な Unicode コードポイントは strconv.QuoteRune のように、 Unicode 置換文字 U+FFFD に変更される。
これだけではなかなかイメージがつかなかったので、実際に試してみました。
package main import ( "fmt" ) func main() { str := "Gopherくん" slice := []string{"g", "o", "h", "e", "r"} integer := 12450 fmt.Printf("1:出力は %q となります。\n", str) fmt.Printf("2:出力は %s となります。\n", str) fmt.Printf("3:出力は %q となります。\n", slice) fmt.Printf("4:出力は %s となります。\n", slice) fmt.Printf("5:出力は %d となります。\n", integer) fmt.Printf("6:出力は %q となります。\n", integer) }
実行してみると以下のように出力されました。
1:出力は "Gopherくん" となります。 2:出力は Gopherくん となります。 3:出力は ["g" "o" "h" "e" "r"] となります。 4:出力は [g o h e r] となります。 5:出力は 12450 となります。 6:出力は 'ア' となります。
このように、文字列型とスライス型の場合は、ダブルクォーテーション("")で囲まれて出力されます。 整数型の場合は、シングルクォート('')で囲まれた文字列リテラルにフォーマットされて出力されます。 なので、6の場合は、アのUnicode コードポイントが10進数表記で12450なので、'ア'が出力されます。
%qの使いどころ
こちらの記事を参照させていただいたのですが、
例えばエラー出力の際に、
u, err := url.Parse(r.Image.URL) if err != nil { return nil, fmt.Errorf("画像URLの形式が正しくありません: %q : %w", r.Image.URL, err) }
エラーになった場合でr.Image.URLが空の場合には、 %sを使うと出力は
画像URLの形式が正しくありません: : hogehogeerror
のようになるのですが、%q を使うと出力は
画像URLの形式が正しくありません: "" : hogehogeerror
となり、r.Image.URLが空になっているというのを少しだけわかりやすくすることができます!
なので、文字列を出力する際に、空になる可能性があるなら%q を使うと良いということがわかりました。
終わりに
もしこの記事の内容についてご指摘等ございましたら、お気軽に教えていただけると嬉しいです!!
ここまで読んでいただいて本当にありがとうございます。
参考にさせていただいた資料
fmt package - fmt - Go Packages
Strings, bytes, runes and characters in Go - The Go Programming Language
The Go Programming Language Specification - The Go Programming Language