Go字符串拼接的5种方法(新手必看)
字符串拼接是指将两个字符串连接起来,构成一个新的字符串。
字符串拼接在 Go 语言日常开发中很常见,可以使用多种方法实现,比如:
另外,在将原字符串和待拼接字符串复制到新的字符串中后,还要把新的字符串赋值给变量,这就导致产生了很多临时、无用的字符串,给垃圾回收增加了负担,进而导致性能变差。
fmt.Sprintf() 函数内部是使用 []byte 实现的,所以不会像直接使用“+”那样产生较多的临时字符串。但是 fmt.Sprintf() 函数内部的实现逻辑比较复杂,有很多额外的判断,而且还用到了接口,所以性能也不好。
另外需要注意的是,不应调用 Sprintf() 函数来构造 String() 方法,这是容易犯错的地方。如果调用 Sprintf() 函数尝试直接输出字符串,而该字符串又再次调用该方法,就会形成无限递归。示例代码如下:
具体方法为先根据字符串数组的内容计算拼接后的长度,然后申请对应大小的内存,最后填充字符串。在已有一个数组的情况下,使用该函数的效率很高。
示例代码如下:
bytes.Buffer 内部维护了一个字节切片,向字节切片添加字符串时,实际上是将字符串的字节内容追加到该字节切片中。
可以通过 String() 方法将字节切片转换为字符串。使用 bytes.Buffer 的 WriteString() 方法可以将传入的字符串写入缓冲切片中。示例代码如下:
所以在 Go1.10 版本中新增了 strings.Builder,它的底层实现原理与 bytes.Buffer 类似。官方建议使用 strings.Builder 对字符串进行拼接,使用 bytes.Buffer 对 byte 进行拼接。
关键代码如下:
字符串拼接在 Go 语言日常开发中很常见,可以使用多种方法实现,比如:
- 使用运算符“+”;
- 使用 fmt.Sprintf() 函数;
- 使用 strings.Join() 函数;
- 使用 bytes.Buffer;
- 使用 strings.Builder。
运算符“+”拼接字符串
使用运算符“+”拼接字符串是最简单、直观的方法。示例代码如下:s1 := "hello" s2 := "world" s3 := s1 + s2 // s3 = "helloworld" s1 += s2 // s1 = "helloworld"虽然这是最简单、直观的方法,但也是有代价的。由于字符串是只读的,因此每次“原地”修改该字符串时,都会重新创建一个新的字符串。
另外,在将原字符串和待拼接字符串复制到新的字符串中后,还要把新的字符串赋值给变量,这就导致产生了很多临时、无用的字符串,给垃圾回收增加了负担,进而导致性能变差。
fmt.Sprintf()函数拼接字符串
fmt.Sprintf("%s%s", str1, str1) 会根据指定的格式将传入的参数格式化,并返回一个新的字符串对象。fmt.Sprintf() 函数内部是使用 []byte 实现的,所以不会像直接使用“+”那样产生较多的临时字符串。但是 fmt.Sprintf() 函数内部的实现逻辑比较复杂,有很多额外的判断,而且还用到了接口,所以性能也不好。
另外需要注意的是,不应调用 Sprintf() 函数来构造 String() 方法,这是容易犯错的地方。如果调用 Sprintf() 函数尝试直接输出字符串,而该字符串又再次调用该方法,就会形成无限递归。示例代码如下:
type MyString string func (m MyString) String() string { return fmt.Sprintf("MyString=%s", m) // 错误:会形成无限递归 }解决这个问题很简单,将传入参数的类型从自定义的 MyString 转换为基本的字符串类型,这样就不会出现无限递归的问题了。示例代码如下:
type MyString string func (m MyString) String() string { return fmt.Sprintf("MyString=%s", string(m)) // 可以:注意转换 }
strings.Join()函数拼接字符串
strings.Join() 函数以一个字符串切片和一个分隔符作为参数,可将字符串切片中的元素基于指定的分隔符拼接成一个新的字符串对象。具体方法为先根据字符串数组的内容计算拼接后的长度,然后申请对应大小的内存,最后填充字符串。在已有一个数组的情况下,使用该函数的效率很高。
示例代码如下:
str := []string{"学", "习", "Go"} String := strings.Join(str,"") fmt.Println("String = ", String) //输出:String = 学习Go
bytes.Buffer拼接字符串
bytes.Buffer 是 Go 语言内置的一种字节缓冲区。bytes.Buffer 内部维护了一个字节切片,向字节切片添加字符串时,实际上是将字符串的字节内容追加到该字节切片中。
可以通过 String() 方法将字节切片转换为字符串。使用 bytes.Buffer 的 WriteString() 方法可以将传入的字符串写入缓冲切片中。示例代码如下:
var buf bytes.Buffer n, _ := buf.WriteString("学习") fmt.Println("n=", n) //输出:n= 6 fmt.Println("buf=", buf.String()) //输出:buf= 学习 buf.WriteString("Go语言!") fmt.Println("buf=", buf.String()) //输出:buf= 学习Go语言!这种方法适用于需要拼接大量字符串的场景,可以将 bytes.Buffer 用作可变字符。此方法对内存的增长也有优化,如果能预估字符串的长度,还可以用 buffer.Grow() 函数设置容量,其性能要优于前面几种方法。
strings.Builder拼接字符串
上一种方法是使用 bytes 包来操作 string,如果单从字面上来理解,难免让人产生为什么使用 byte 操作 string 的困惑。所以在 Go1.10 版本中新增了 strings.Builder,它的底层实现原理与 bytes.Buffer 类似。官方建议使用 strings.Builder 对字符串进行拼接,使用 bytes.Buffer 对 byte 进行拼接。
关键代码如下:
var builder strings.Builder // strings.Builder的零值可以直接使用 // 在builder中写入字符/字符串 builder.Write([]byte("hello")) builder.WriteByte(' ') builder.WriteString("World") // 使用String()方法获得拼接的字符串 builder.String() // "hello world"从上面的代码中可以看到,strings.Builder 和 bytes.Buffer 的使用方法几乎一样。二者的区别是 strings.Builder 仅实现了写操作,而 bytes.Buffer 将读、写操作都实现了,所以 strings.Builder 仅用于拼接或者构建字符串。