`%q` 和 `%#q` 字符串格式化程序有什么区别?

Hun*_*nam 2 printf string-formatting go

#我不明白当与 一起使用时的含义q

fmt.Printf("%q", "\"")
fmt.Println()
fmt.Printf("%#q", "\"")
Run Code Online (Sandbox Code Playgroud)

印刷

"\""
`"`
Run Code Online (Sandbox Code Playgroud)

"\""
`"`
Run Code Online (Sandbox Code Playgroud)

印刷

"\n"
"\n"
Run Code Online (Sandbox Code Playgroud)

https://cs.opensource.google/go/go/+/master:src/fmt/fmt_test.go有更多示例。

fmt.Printf("%q", "\n")
fmt.Println()
fmt.Printf("%#q", "\n")
Run Code Online (Sandbox Code Playgroud)

bla*_*een 5

%q如果您在 Go 源代码中将其声明为解释字符串文字,则该动词将打印字符串的内容,即使用转义序列并用双引号括起来"

动词的%#q作用相同,但作为原始字符串文字,没有转义序列并用反引号括起来`

fmt文档报告了这个示例:

字符串按原样使用 %v 和 %s 格式化,%q 作为带引号的字符串,%#q 作为反引号字符串。

placeholders := `foo "bar"`   
fmt.Printf("%v %s %q %#q\n", placeholders, placeholders, placeholders, placeholders)  
// Result: foo "bar" foo "bar" "foo \"bar\"" `foo "bar"`
Run Code Online (Sandbox Code Playgroud)

假设您要声明一个内容为字符的字符串变量"。你会如何在 Go 源代码中编写它?对于解释的字符串文字,您必须对其进行转义,而对于原始字符串文字,您只需将其括在反引号中。所以:

  • 其输出%q"\""您可以将 Go 代码复制粘贴为解释的字符串文字。

  • %#q您可以将其输出`"`作为原始字符串文字复制粘贴到 Go 代码中。

当您的字符串包含应转义的字符时,这最相关。

换句话说:

func main() {
    v := "\""
    w := `"`
    fmt.Printf("%q\n", v)  // prints "\"", same as I just declared v
    fmt.Printf("%#q\n", w) // prints `"`, same as I just declared w
}
Run Code Online (Sandbox Code Playgroud)

作为此复制粘贴用例的副作用,任一格式动词的实际应用是检查字符串变量的运行时值中是否有不可见字符,如果您在 Go 源代码中使用它,则必须以某种方式输入这些字符。

有一个特殊情况值得一提,也可以在fmt包文档中找到:

#替代格式:[...] 对于 %q,如果 strconv.CanBackquote 返回 true,则打印原始(反引号)字符串;[...]

并跳转到以下文档strconv.CanBackquote

CanBackquote 报告字符串 s 是否可以不变地表示为不带制表符以外的控制字符的单行反引号字符串。

值得注意的是,CanBackquote对于包含反引号字符本身或换行符的字符串返回 false \n,因为在后一种情况下,字符串不能表示为单行。(另请参阅如何在 Go 中编写多行字符串?

因此,在这些情况下,该标志#将不起作用,并且%#q打印的内容与 相同%q

func main() {
    v := "\n"
    w := `
`
    fmt.Printf("%q\n", v)  // prints "\n", same as I just declared v
    fmt.Printf("%#q\n", w) // prints "\n" too, because CanBackquote returns false
}
Run Code Online (Sandbox Code Playgroud)