Golang 字符串拼接

作者: Gundy_ | 来源:发表于2019-04-03 16:31 被阅读3次

字符串拼接应该在编程过程中比较常用的操作了,在Go语言中对字符串的拼接有多种处理方式,以下通过实例来一一讲解

+号拼接

这种应该是最直接最简单的方式了。

func StringPlus() string {
    var s string
    s = "社会主义核心价值观的基本内容:"
    s += "富强、民主、文明、和谐,是我国社会主义现代化国家的建设目标;"
    s += "自由、平等、公正、法治,是对美好社会的生动表述;"
    s += "爱国、敬业、诚信、友善”,是公民基本道德规范。"
    return s
}

运行go test -bench=. -benchmem 查看性能输出如下:
BenchmarkStringPlus-8 5000000 251 ns/op 640 B/op 3 allocs/op

fmt拼接

func StringFmt() string  {
    return fmt.Sprint("社会主义核心价值观的基本内容:",
        "富强、民主、文明、和谐,是我国社会主义现代化国家的建设目标;,",
        "自由、平等、公正、法治,是对美好社会的生动表述;",
        "爱国、敬业、诚信、友善”,是公民基本道德规范。")
}

BenchmarkStringPlus-8 10000000 234 ns/op 288 B/op 1 allocs/op

Join拼接

这个是利用strings.Join函数进行拼接,接受一个字符串数组,转换为一个拼接好的字符串。

func StringJoin() string {
    s := []string{"社会主义核心价值观的基本内容:", "富强、民主、文明、和谐,是我国社会主义现代化国家的建设目标;",
        "自由、平等、公正、法治,是对美好社会的生动表述;",
        "爱国、敬业、诚信、友善”,是公民基本道德规范。"}
    return strings.Join(s, ",")
}

BenchmarkStringPlus-8 10000000 189 ns/op 576 B/op 2 allocs/op

buffer

func StringBuffer() string {
    var b bytes.Buffer
    b.WriteString("社会主义核心价值观的基本内容:")
    b.WriteString("富强、民主、文明、和谐,是我国社会主义现代化国家的建设目标;")
    b.WriteString("自由、平等、公正、法治,是对美好社会的生动表述;")
    b.WriteString("爱国、敬业、诚信、友善”,是公民基本道德规范。")

    return b.String()
}

BenchmarkStringPlus-8 3000000 505 ns/op 1136 B/op 4 allocs/op

builder

func StringBuilder() string {
    var  s strings.Builder
    s.WriteString("社会主义核心价值观的基本内容:")
    s.WriteString("富强、民主、文明、和谐,是我国社会主义现代化国家的建设目标;")
    s.WriteString("自由、平等、公正、法治,是对美好社会的生动表述;")
    s.WriteString("爱国、敬业、诚信、友善”,是公民基本道德规范。")

    return s.String()
}

BenchmarkStringBuffer10-8 10000000 200 ns/op 480 B/op 3 allocs/op

以上是进行了五次字符串的拼接,可以看到buffer的性能较差一些,其他大致三种方式区别不大

那么100个字符串1000个字符串拼接又如何呢

package main

import (
    "bytes"
    "fmt"
    "strings"
)

func StringPlus(p []string) string {
    var s string
    l := len(p)
    for i := 0; i < l; i++ {
        s += p[i]
    }
    return s
}

func StringFmt(p []interface{}) string {
    return fmt.Sprint(p...)
}

func StringJoin(p []string) string {
    return strings.Join(p, "")
}

func StringBuffer(p []string) string {
    var b bytes.Buffer
    l := len(p)
    for i := 0; i < l; i++ {
        b.WriteString(p[i])
    }
    return b.String()
}

func StringBuilder(p []string) string {
    var b strings.Builder
    l := len(p)
    for i := 0; i < l; i++ {
        b.WriteString(p[i])
    }
    return b.String()
}

进行如下压测

package main

import "testing"

const WebSite  = "https://www.china.com/"

const StringLen = 1000

func initStrings(N int) []string{
    s:=make([]string,N)
    for i:=0;i<N;i++{
        s[i]=WebSite
    }
    return s
}

func initStringi(N int) []interface{}{
    s:=make([]interface{},N)
    for i:=0;i<N;i++{
        s[i]=WebSite
    }
    return s
}

func BenchmarkStringPlus10(b *testing.B) {
    p:= initStrings(StringLen)
    b.ResetTimer()
    for i:=0;i<b.N;i++{
        StringPlus(p)
    }
}

func BenchmarkStringFmt10(b *testing.B) {
    p:= initStringi(StringLen)
    b.ResetTimer()
    for i:=0;i<b.N;i++{
        StringFmt(p)
    }
}

func BenchmarkStringJoin10(b *testing.B) {
    p:= initStrings(StringLen)
    b.ResetTimer()
    for i:=0;i<b.N;i++{
        StringJoin(p)
    }
}

func BenchmarkStringBuffer10(b *testing.B) {
    p:= initStrings(StringLen)
    b.ResetTimer()
    for i:=0;i<b.N;i++{
        StringBuffer(p)
    }
}

func BenchmarkStringBuilder10(b *testing.B) {
    p:= initStrings(StringLen)
    b.ResetTimer()
    for i:=0;i<b.N;i++{
        StringBuilder(p)
    }
}

压测结果如下:

BenchmarkStringPlus10-8             1000           1905639 ns/op        11573410 B/op        999 allocs/op
BenchmarkStringFmt10-8             50000             32464 ns/op           24586 B/op          1 allocs/op
BenchmarkStringJoin10-8           100000             17600 ns/op           49152 B/op          2 allocs/op
BenchmarkStringBuffer10-8          50000             27480 ns/op          122544 B/op         11 allocs/op
BenchmarkStringBuilder10-8        100000             20535 ns/op           96224 B/op         16 allocs/op

可以看到Join 和 builder表现最好。但是一般是有数组切片进行字符串拼接我们采用join, 如果没有的话还是builder更合适。

builder 优化

查看WriteString的源码我们可以发现,这里有对b.buf进行append操作,那对于长的字符串就会触发扩容操作影响性能

func (b *Builder) WriteString(s string) (int, error) {
    b.copyCheck()
    b.buf = append(b.buf, s...)
    return len(s), nil
}

由于扩容导致的问题,那我们是否可以事先分配好所需的容量呢,查看buIlder源码发现提供了一个Grow方法,正是来进行容量分配的。

func (b *Builder) grow(n int) {
    buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
    copy(buf, b.buf)
    b.buf = buf
}

那我们你可以优化StringBuilder如下:

func StringBuilder(p []string,cap int) string {
    var b strings.Builder
    l:=len(p)
    b.Grow(cap)
    for i:=0;i<l;i++{
        b.WriteString(p[i])
    }
    return b.String()
}

本文亦在微信公众号【小道资讯】发布,欢迎扫码关注!


image

相关文章

  • go 实现 implode 方法

    impolde 方法是 php 中常用的字符串拼接方法, 在golang 中也有字符串拼接的函数: 此函数与imp...

  • go字符串拼接与性能分析

    字符串拼接在golang中是非常常见的操作,本文介绍几种常用方法并分析各种方法的效率. 拼接 + 号拼接 + 号拼...

  • golang 几种字符串的连接方式

    最近在做性能优化,有个函数里面的耗时特别长,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在 golang ...

  • [golang]字符串拼接

    这几天研究了一下golang的字符串拼接哪种效率最高。 结论是,如果是比较简单的拼接,或者是一次性的,那么哪种方法...

  • Golang 字符串拼接

    字符串拼接应该在编程过程中比较常用的操作了,在Go语言中对字符串的拼接有多种处理方式,以下通过实例来一一讲解 +号...

  • golang高效拼接字符串

    在循环中使用加号 + 拼接字符串并不是最高效的做法,更好的办法是使用函数 strings.Join()有没有更好地...

  • Golang 高效字符串拼接

    go 用 strings.Builder 代替普通的 + 号拼接, 在本人的项目中性能有 8 ~15倍的提升,之...

  • R 包学习 - stringr()

    stringr: R 语言字符串处理包 字符串拼接函数str_c: 字符串拼接。str_join: 字符串拼接,同...

  • golang拼接字符串性能测试

    直接下结论:bufferTest > plusTest ~= JoinTest > sprintfTest结果如下...

  • Swift5.0 字符串(String)详解

    1.字符串拼接 + 拼接 \() 拼接 2.字符串是否为空判断 3.字符串长度 4.字符串比较 == > < 5....

网友评论

    本文标题:Golang 字符串拼接

    本文链接:https://www.haomeiwen.com/subject/wpczbqtx.html