高效操作Golang字符串实战教程

Go可以对字符串直接连接,但更有效的方法是是使用Builder结构,和java中StringBuffer类似。本文介绍如何通过strings.Builder高效构建字符串,通过示例介绍WriteString 和 WriteRune方法,并进行性能对比builder的优势。最后列出常用的字符串操作方法。

Builder介绍

Builder是Go内置结构体,源码如下:

// A Builder is used to efficiently build a string using Write methods.
// It minimizes memory copying. The zero value is ready to use.
// Do not copy a non-zero Builder.
type Builder struct {
	addr *Builder // of receiver, to detect copies by value
	buf  []byte
}

其内部为字节数组,动态分配内存,但不是每次都分配:

// grow copies the buffer to a new, larger buffer so that there are at least n
// bytes of capacity beyond len(b.buf).
func (b *Builder) grow(n int) {
	buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
	copy(buf, b.buf)
	b.buf = buf
}

// Grow grows b's capacity, if necessary, to guarantee space for
// another n bytes. After Grow(n), at least n bytes can be written to b
// without another allocation. If n is negative, Grow panics.
func (b *Builder) Grow(n int) {
	b.copyCheck()
	if n < 0 {
		panic("strings.Builder.Grow: negative count")
	}
	if cap(b.buf)-len(b.buf) < n {
		b.grow(n)
	}
}

WriteString方法

下面示例使用strings.Builder构建字符串:

package main

import (
    "fmt"
    "strings"
)

func main() {

    builder := strings.Builder{}

    builder.WriteString("There")
    builder.WriteString(" are")
    builder.WriteString(" three")
    builder.WriteString(" hawks")
    builder.WriteString(" in the sky")

    fmt.Println(builder.String())
}

使用WriteString方法构建字符串,输出结果为:

go run simple.go 
There are three hawks in the sky

Write方法

下面示例通过字节slice构建字符串:

package main

import (
    "fmt"
    "strings"
)

func main() {

    builder := strings.Builder{}

    data1 := []byte{72, 101, 108, 108, 111}
    data2 := []byte{32}
    data3 := []byte{116, 104, 101, 114, 101, 33}

    builder.Write(data1)
    builder.Write(data2)
    builder.Write(data3)

    fmt.Println(builder.String())
}

上面示例通过Write方法构建字符串,输出结果为:

go run simple2.go 
Hello there!

另外还有 builder.WriteByte(),builder.WriteRune()方法,每次写一个字节。

性能对比

下面比较Builder与字符串连接的性能:

package main

import (
    "fmt"
    "strings"
    "time"
)

func main() {

    t0 := time.Now()

    builder := strings.Builder{}
    for i := 0; i < 100_000; i++ {
        builder.WriteString("falcon")
    }

    t1 := time.Now()

    result := ""
    for i := 0; i < 100_000; i++ {
        result += "falcon"
    }

    t2 := time.Now()

    fmt.Println(t1.Sub(t0))
    fmt.Println(t2.Sub(t1))
}

上面示例对比两种方法,分别连接字符串10万次。运行结果为:

1.0285ms
2.8703108s

其他字符串连接方法

strings.Join

Join连接slice/array的元素:

package main

import (
    "fmt"
    "strings"
)

func main() {

    words := []string{"an", "old", "falcon"}
    msg := strings.Join(words, " ")

    fmt.Println(msg)
}

fmt.Sprintf

使用格式连接字符串:

package main

import "fmt"

func main() {

    w1 := "old"
    w2 := "falcon"

    msg := fmt.Sprintf("%s %s", w1, w2)

    fmt.Println(msg)
}

bytes.Buffer

与strings.Builder原理一致,读者可以查看其源码:

package main

import (
    "bytes"
    "fmt"
)

func main() {

    var buf bytes.Buffer

    buf.WriteString("an ")
    buf.WriteString("old ")
    buf.WriteString("falcon")

    fmt.Println(buf.String())
}

当然也可以slice实现:

package main

import (
    "fmt"
)

func main() {

    var s1 = "an"
    var s2 = " old"
    var s3 = " falcon"

    msg := make([]byte, 0)

    msg = append(msg, []byte(s1)...)
    msg = append(msg, []byte(s2)...)
    msg = append(msg, []byte(s3)...)

    fmt.Println(string(msg))
}

加号操作符

最后还在提及下加号操作:

package main

import "fmt"

func main() {

    w1 := "an"
    w2 := " old"
    w3 := " falcon"

    msg := w1 + w2 + w3
    fmt.Println(msg)

    str := "There are"

    str += " three falcons"
    str += " in the sky"
    fmt.Println(str)
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值