2

I don't get the meaning of # when used with q.

fmt.Printf("%q", "\"")
fmt.Println()
fmt.Printf("%#q", "\"")

prints

"\""
`"`

but

fmt.Printf("%q", "\n")
fmt.Println()
fmt.Printf("%#q", "\n")

prints

"\n"
"\n"

There are more examples at https://cs.opensource.google/go/go/+/master:src/fmt/fmt_test.go.

{"%q", "", `""`},
{"%#q", "", "``"},
{"%q", "\"", `"\""`},
{"%#q", "\"", "`\"`"},
{"%q", "`", `"` + "`" + `"`},
{"%#q", "`", `"` + "`" + `"`},
{"%q", "\n", `"\n"`},
{"%#q", "\n", `"\n"`},
{"%q", `\n`, `"\\n"`},
{"%#q", `\n`, "`\\n`"},
{"%q", "abc", `"abc"`},
{"%#q", "abc", "`abc`"},
Hunam
  • 69
  • 1
  • 10

2 Answers2

5

The verb %q prints the contents of a string as it appears if you declared it as an interpreted string literal in your Go source code, i.e. with escape sequences and enclosed in double quotes ".

The verb %#q does the same, but as a raw string literal, with no escape sequences and enclosed in backquotes `.

The fmt package documentation reports this example:

Strings are formatted with %v and %s as-is, with %q as quoted strings, and %#q as backquoted strings.

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

Let's say you want to declare a string variable whose content is the character ". How would you write that in your Go source? With an interpreted string literal, you would have to escape it, and with a raw string literal you would just enclose it in backquotes. Therefore:

  • The output of %q is "\"" that you can copy-paste in Go code as an interpreted string literal.

  • The output of %#q is `"` that you can copy-paste in Go code as a raw string literal.

This is mostly relevant when your string contains characters that should be escaped.

In other words:

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
}

As a side effect of this copy-paste use case, a practical application of either format verb is to inspect the run-time value of string variables for invisible characters, which you would have to type out somehow if you used it in Go source code.

There's one special case worth mentioning, which is also found in the fmt package docs:

# alternate format: [...] for %q, print a raw (backquoted) string if strconv.CanBackquote returns true; [...]

And jump to the docs of strconv.CanBackquote:

CanBackquote reports whether the string s can be represented unchanged as a single-line backquoted string without control characters other than tab.

Notably, CanBackquote returns false for strings that contain the backquote character itself or newline character \n, as in the latter case the string can not be represented as a single-line. (See also How do you write multiline strings in Go?)

So in these cases the flag # would have no effect and %#q would print the same as %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
}
blackgreen
  • 34,072
  • 23
  • 111
  • 129
0

%q prints the value as a quoted string.
%#q prints the value as a quoted string as Go syntax.

In general, adding # between % and the type causes output to be in Go code - syntactically correct that you could copy-paste into your program.

This example illustrates the effect of the #:

s := []string{"foo", "bar", "baz"}
fmt.Printf("%v\n", s)
fmt.Printf("%#v\n", s)
fmt.Printf("%q\n", s)
fmt.Printf("%#q\n", s)

Produces:

[foo bar baz]
[]string{"foo", "bar", "baz"}
["foo" "bar" "baz"]
[`foo` `bar` `baz`]

See live demo.

Bohemian
  • 412,405
  • 93
  • 575
  • 722