Learning Golang: Multiline strings
This is part 7 of my journey learning Golang.
My first assignment on Codecademy’s Learn Go course was to create a program that prints out ASCII art.
The way that’s different from a “Hello, World” program is that it needs to print multiple lines. So it was a great opportunity to learn about how multi-line strings can be represented in Go.
Go’s string literals
String literals represent “string constants” i.e. immutable string values in a Go source file.
There are two ways of declaring string literals in Go: using quotes and using backticks. The first one declares an “interpreted string”, and the second one a “raw string”. There are also “rune literals”, which are not properly strings, but represent a single character.
Interpreted strings
A string literal declared between double quotes ("
) is an interpreted string.
The characteristics of interpreted strings are:
- They can span a single line in the source file.
- They can contain any character except for a “raw” newline or an unescaped double quote.
- Backslash escapes are interpreted.
Examples:
1"foo" // The word foo
2"foo\nbar" // foo, newline, and bar
3"Saudações" // UTF-8 text
4"Sauda\u00E7\u00F5es" // Unicode code points (same text as above)
Raw strings
A string literal declared between backticks (AKA “back quotes”) is a raw string. It has these characteristics:
- It can span multiple lines in the source code.
- The raw newlines in the source file become newlines in the string constant.
- It doesn’t interpret escape sequences.
- It can’t include backticks (not even via escaping; see above).
Rune literals
Quoting Go’s documentation, “a rune literal represents a rune constant, an integer value identifying a Unicode code point.” Conceptually it represents a single character (keeping in mind that it’s Unicode).
Run literals also interpret backslash escapes.
Examples:
1'a'
2'ã'
3'\t'
4'\377'
5'\xff'
6'\u12e4'
7'\U00101234'
ASCII art in Go source code
The ASCII art that I wanted to print from my first Go program made liberal use of all sorts of symbols like backticks (`), single quotes (') and backslashes (\). It also had multiple lines, of course.
I had a few alternatives for representing it in a source file:
- Between double quotes: I’d need to break it down into multiple string constants (one per line) and escape the backslash and double quote characters. It would work, but it would look distorted in the source file.
- A very long, single-line interpreted script, with escaped newline characters. That’s unwieldy.
- Between backticks: I’d have a single multi-line string, and I wouldn’t need to escape anything. But I wouldn’t be able to use backticks in the string itself.
Another alternative of course would be to not embed the string in a Go source file, but that is outside the goal of the exercise. In fact this exercise was quite clever because it forced me to learn a lot about string literals in Go.
I decided to go with option 3 – backticks – mainly because the embedded string looks better in a Go source file if it isn’t escaped. I compromised by replacing the backtick characters with backslashes in the ASCII art.
This was my end result:
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 // Credit: unknown artist.
9 fmt.Println(` 888888888888888888888
10 s 88 ooooooooooooooo 88 s 888888888888888888888888888888888888888
11 S 88 888888888888888 88 SS 888888888888888888888888888888888888888
12 SS 88 888888888888888 88 SSS 8888 - --+ 8888
13 SS 88 ooooooooooooooo 88 sSSS 8888 o8888888o | 8888
14sSS 88 888888888888888 88 SSSSS 8888 o88888888888o 8888
15SSS 88 888888888888888 88 SSSSS 8888 8888 88888 8888 | 8888
16SSS 88 ooooooooooooooo 88 SSSSS 8888 o888 888 888o 8888
17SSS 88 888888888888888 88 SSSSS 8888 8888 888 8888 8888
18SSS 88 888888888888888 88 SSSSS 8888 8888 888 8888 8888
19SSS 88 oooooooooo 88 SSSSS 8888 8888o o888o o8888 8888
20SSS 88 8888888888 .::. 88 SSSSS 8888 988 8o88888o8 88P 8888
21SSS 88 oooooooooo :::: 88 SSSSS 8888 8oo 9888889 oo8 8888
22SSS 88 8888888888 \' 88 SSSSS 8888 988o o88P 8888
23SSS 88ooooooooooooooooo88 SSSS 8888 98888888P 8888
24SSS 888888888888888888888__SSSS 8888 8888_____
25SSS | * * * )8c8888 SSSS 888888888888888888888888888888888888888
26SSS 888888888888888888888. SSS 888888888888888888888888888888888888888
27SSS 888888888888888888888 \_ SSsssss oooooooooooooooooooooooooooo ssss
28SSS 888888888888888888888 \\ __SS 88+-8+-88============8-8==88 S
29SSS 888888888888888888888-. \\ \ S 8888888888888888888888888888
30SSS 888888888888888888888 \\\ \\ \.__________.' \ .
31SSS 88O8O8O8O8O8O8O8O8O88 \\. \\______________________________\_.
32SSS 88 el cheapo 8O8O8O88 \\ '. \|________________________________|
33 SS 88O8O8O8O8o8O8O8O8O88 \\ '-.___
34 S 888888888888888888888 /~ ~~~~~-----~~~~---.__
35 .---------------------------------------------------. ~--.
36 \ \______\ __________________________________________\-------^.-----------.
37 :' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \\ \
38 ::\ ,\_\,\_\_\_\_\\_\_\_\_\\_\_\_\_\,\_\_\_\ \ o '8o 8o .
39 |::\ -_-_-_-_-_-_-_-_-_-_-_-_-_-___ -_-_-_ _ _ _ _ \ 8o 88 88 \
40 |_::\ ,\_\_\_\_\_\_\_\_\_\_\_\_\_\___\,\_\_\_\,\_\_\_\_\ \ 88 \
41 \:\ ,\__\_\_\_\_\_\_\_\_\_\_\_\_\ \,\_\_\_\,\_\_\_\ \ \ 88 .
42 \:\ ,\__\_\_\_\_\_\_\_\_\_\_\_\____\ _ ,\_\_\_\_\ \ 88o .|
43 :\ ,\____\_\_\_\_\_\_\_\_\_\_\____\ ,\_\ _,\_\_\_\ \ \ 'ooooo'
44 :\ ,\__\\__\_______________\__\\__\,\_\_\_\,\___\_\_\ \
45 \\ -- -- --------------- -- -- - - - --- - - )____________
46 \--------------------------------------------------'
47`)
48}
Source: learning-go/ascii-art/main.go
Takeaways
Go offers 3 ways to represent string or character literals:
Syntax | Symbol | Span | Escaping |
---|---|---|---|
Interpreted strings | double quotes (" ) |
Single source line | Yes |
Raw strings | backticks (` ) |
Multiple source lines | No |
Rune literals | single quotes (' ) |
Single code point | Yes |
What else would you point out about strings in Go?
comments powered by Disqus