如何在Go语言中编写多行字符串?

901

Go语言中是否有类似Python多行字符串的东西:

"""line 1
line 2
line 3"""

如果没有,那么编写跨多行的字符串的首选方法是什么?


Go语言:区分\r和\n请使用 strings.Split 函数将输入的字符串按照 "\r" 或 "\n" 分割成多个子字符串,并打印出来。 - Lalit Sharma
13个回答

1387
根据语言规范,您可以使用原始字符串字面量,其中字符串由反引号而不是双引号括起来。
`line 1
line 2
line 3`

212
顺便提一下,所谓的“原始引用”不会解析转义序列。 因此,它是编写正则表达式模式的首选字符串文字,因为它们通常包含非标准转义序列,这会导致Go编译器抱怨未双重转义。 这使得模式保持干净且相对易读。 - jimt
13
使用行末空格时需要小心。例如,如果在“line 1”后面加上一个空格,它将在编辑器中看不见但会存在于字符串中。 - Ory Band
2
@DanieleD 这有点跳跃,但是指的是哪个方言?大概主要是MySQL吧?https://dev59.com/F2kv5IYBdhLWcg3wdQvm#10574031 请注意,按照同样的论点推论,这对于嵌入markdown或shell脚本(如果您选择使用反引号代替$(abcd))也很麻烦。 - Ivan Vučica
11
据推测,Daniele D 在他/她的 SQL 查询中使用反引号字符(正如 MySQL 用户经常这样做),并且发现将其表示为 ` + "`" + ` 并破坏复制粘贴功能很麻烦。 - ruakh
2
如果使用MySQL时遇到问题,请注意您可以始终设置会话SQL模式,例如 SET SESSION sql_mode ='ANSI_QUOTES'; 这将“将双引号视为标识符引用字符(如反引号引用字符),而不是字符串引用字符。” 然后只需确保对于每个SQL数据库都使用撇号 ' 作为字符串文字。请参见 https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_ansi_quotes - Davos
显示剩余5条评论

176

你可以这样写:

"line 1" +
"line 2" +
"line 3"

这与以下代码相同:

"line 1line 2line 3"

使用双引号不同于使用反引号,它将保留转义字符。请注意,“+” 必须在“前导”的行上 - 例如,以下内容将会生成错误:

"line 1"
+"line 2"

42
这个解决方案与Python的多行字符串不是类似的。它将字符串文字分成多行,但字符串本身并不包含多行。 - Ben Butler-Cole
3
由于这种方法会保留转义字符,因此可以通过\n轻松添加新行,这样就更容易处理动态字符串等。如果我没错的话,被接受的答案确实是用于静态代码字符串的美观呈现。 - RisingSun
2
这样做效率也会非常低下,让字符串成为一个6个字符序列的3倍:6 + 26 +36 = 36个字符被分配,而最优的情况应该是18个字符(因为字符串是不可变的,每次添加两个字符串时都会创建一个新的字符串,其长度为连接的两个字符串的长度)。 - N0thing
我认为这是使用CRLF行结束符获取多行字符串字面值的最佳方法。 - ldanilek
这在 fmt.Sprintf("非常长的动态字符串,例如 SQL") 上运行得非常好。 - coanor
显示剩余2条评论

64

使用原始字符串字面量来表示多行字符串:

func main(){
    multiline := `line 
by line
and line
after line`
}

原始字符串字面量

原始字符串字面量是用反引号括起来的字符序列,例如`foo`。在引号内,任何字符都可以出现,除了反引号。

重要的是原始字面量而不仅仅是多行文本,其目的也不仅仅是支持多行文本。

原始字符串字面量的值是由引号之间未解释的(隐含UTF-8编码)字符组成的字符串;特别地,反斜杠没有特殊意义......

所以转义字符将不会被解释和反引号之间的换行符将成为真正的换行符

func main(){
    multiline := `line 
by line \n
and line \n
after line`

    // \n will be just printed. 
    // But new lines are there too.
    fmt.Print(multiline)
}

连接字符串

可能你有一行很长的文本需要断开成多行显示,但是你不想在其中插入新的换行符。这时候你可以使用字符串连接来实现。

func main(){
    multiline := "line " +
            "by line " +
            "and line " +
            "after line"

    fmt.Print(multiline) // No new lines here
}

由于“”是解释型字符串文字,因此转义字符将被解释。

func main(){
    multiline := "line " +
            "by line \n" +
            "and line \n" +
            "after line"

    fmt.Print(multiline) // New lines as interpreted \n
}

47

字符串字面值

  • 原始字符串字面值支持多行(但转义字符不被解释)
  • 解释的字符串字面值会解释转义字符,如 '\n'。

但是,如果您的多行字符串必须包含反引号(`),则必须使用解释的字符串字面值:

`line one
  line two ` +
"`" + `line three
line four`

您不能在原始字符串字面值中直接放置反引号 (`) (``xx\)。
您必须使用以下方法(正如在“如何在反引号字符串中放置反引号?”中所解释的那样):

 + "`" + ...

16

Go和多行字符串

使用反引号可以创建多行字符串:

package main

import "fmt"

func main() {

    message := `This is a 
Multi-line Text String
Because it uses the raw-string back ticks 
instead of quotes.
`

    fmt.Printf("%s", message)
}

使用反引号(`)来定义字符串的开始和结束,而不是双引号(“)或单引号符号(‘)。然后可以跨行包装它。

如果缩进字符串,则请记住空格将会被计算在内。

请检查playground并进行实验。


9
在Go语言中创建多行字符串实际上非常简单。只需在声明或分配字符串值时使用反引号(`)字符即可。
package main

import (
    "fmt"
)

func main() {
    // String in multiple lines
    str := `This is a
multiline
string.`
    fmt.Println(str + "\n")
    
    // String in multiple lines with tab
    tabs := `This string
        will have
        tabs in it`
    fmt.Println(tabs)
}

5
您可以使用 `` 将内容包含在其中,例如

var hi = `I am here,
hello,
`

4

在Go语言中,格式和行间距非常重要。每一个细节都需要注意。下面是一个可运行的代码样例,请尝试:https://play.golang.org/p/c0zeXKYlmF

package main

import "fmt"

func main() {
    testLine := `This is a test line 1
This is a test line 2`
    fmt.Println(testLine)
}

3

您可以使用原始文字。例如:

s:=`stack
overflow`

3

对于我来说,我需要使用`反引号/重音符号,并且只需编写一个简单的测试。

+ "`" + ...

这个东西不美观且不方便

所以我用一个字符例如:U+1F42C来代替它


一个演示

myLongData := `line1
line2 aaa
line3
` // maybe you can use IDE to help you replace all ` to 
myLongData = strings.ReplaceAll(myLongData, "", "`")

性能和内存评估

+ "`"replaceAll(, "", "`") 的比较

Go Playground

package main

import (
    "strings"
    "testing"
)

func multilineNeedGraveWithReplaceAll() string {
    return strings.ReplaceAll(`line1
line2
line3 aaa`, "", "`")
}

func multilineNeedGraveWithPlus() string {
    return `line1
line2
line3` + "`" + "aaa" + "`"
}

func BenchmarkMultilineWithReplaceAll(b *testing.B) {
    for i := 0; i < b.N; i++ {
        multilineNeedGraveWithReplaceAll()
    }
}

func BenchmarkMultilineWithPlus(b *testing.B) {
    for i := 0; i < b.N; i++ {
        multilineNeedGraveWithPlus()
    }
}

命令提示符

go test -v -bench=. -run=none -benchmem 查看更多 testing.B

输出

goos: windows
goarch: amd64
pkg: tutorial/test
cpu: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
BenchmarkMultilineWithReplaceAll
BenchmarkMultilineWithReplaceAll-8    12572316      89.95 ns/op   24 B/op  1 allocs/op
BenchmarkMultilineWithPlus
BenchmarkMultilineWithPlus-8          1000000000   0.2771 ns/op    0 B/op  0 allocs/op
PASS
ok      tutorial/test   7.566s

是的,+ "`" 的性能比其他方式更好。


那会很慢(除非你只做一次)。最好使用单独的字符串并连接,因为编译器很可能在字面字符串之间在编译时执行它。 - Alexis Wilke
1
嗨,@Alexis Wilke,感谢提醒。这比那些只投反对票而不留任何评论的人好多了。我添加了性能和内存评估以根据需求决定使用哪一个。 - Carson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接