加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

使用切片值的Golang字符串格式

发布时间:2020-12-16 19:04:14 所属栏目:大数据 来源:网络整理
导读:在这里,我尝试从包含字符串的切片为我的API创建查询字符串. 即.其中= { “的node_name”: “节点1”,“节点名称”: “node_2”} import ( "fmt" "strings")func main() { nodes := []string{"node1","node2"} var query string for _,n := range nodes { q
在这里,我尝试从包含字符串的切片为我的API创建查询字符串.

即.其中= { “的node_name”: “节点1”,“节点名称”: “node_2”}

import (
   "fmt"
   "strings"
)

func main() {
    nodes := []string{"node1","node2"}
    var query string
    for _,n := range nodes {
        query += fmt.Sprintf(""node_name":"%s",",n)
    }
    query = strings.TrimRight(query,")
    final := fmt.Sprintf("where={%s}",query)
    fmt.Println(final)
}

这是goplayground链接.

获得结果的最佳方法是什么?

由于字符串连接,您的解决方案使用了太多的分配.

我们将创建一些替代的,更快的和/或更优雅的解决方案.请注意,下面的解决方案不会检查节点值是否包含引号“character.如果愿意,那些必须以某种方式进行转义(否则结果将是无效的查询字符串).

完整的可运行代码可以在Go Playground上找到.完整的测试/基准测试代码也可以在Go Playground上找到,但它不可运行,只保存到Go工作区(例如$GOPATH / src / query / query.go和$GOPATH / src / query / query_test.go)并使用go test -bench运行它.

另请务必查看以下相关问题:How to efficiently concatenate strings in Go?

备择方案

创世纪

您的逻辑可以通过以下函数捕获:

func buildOriginal(nodes []string) string {
    var query string
    for _,")
    return fmt.Sprintf("where={%s}",query)
}

使用bytes.Buffer

更好的是使用单个缓冲区,例如bytes.Buffer,在其中构建查询,并在结尾处将其转换为字符串:

func buildBuffer(nodes []string) string {
    buf := &bytes.Buffer{}
    buf.WriteString("where={")
    for i,v := range nodes {
        if i > 0 {
            buf.WriteByte(',')
        }
        buf.WriteString(`"node_name":"`)
        buf.WriteString(v)
        buf.WriteByte('"')
    }
    buf.WriteByte('}')
    return buf.String()
}

使用它:

nodes := []string{"node1","node2"}
fmt.Println(buildBuffer(nodes))

输出:

where={"node_name":"node1","node_name":"node2"}

bytes.Buffer改进了

bytes.Buffer仍会进行一些重新分配,尽管比原始解决方案要少得多.

但是,如果我们在使用bytes.NewBuffer()创建bytes.Buffer时传递足够大的字节切片,我们仍然可以将分配减少到1.我们可以先计算所需的大小:

func buildBuffer2(nodes []string) string {
    size := 8 + len(nodes)*15
    for _,v := range nodes {
        size += len(v)
    }
    buf := bytes.NewBuffer(make([]byte,size))
    buf.WriteString("where={")
    for i,')
        }
        buf.WriteString(`"node_name":"`)
        buf.WriteString(v)
        buf.WriteByte('"')
    }
    buf.WriteByte('}')
    return buf.String()
}

请注意,在大小计算中,8是字符串的大小,其中= {},15是字符串“node_name”的大小:“”,.

使用文本/模板

我们还可以创建一个文本模板,并使用text/template包来执行它,有效地生成结果:

var t = template.Must(template.New("").Parse(templ))

func buildTemplate(nodes []string) string {
    size := 8 + len(nodes)*15
    for _,size))
    if err := t.Execute(buf,nodes); err != nil {
        log.Fatal(err) // Handle error
    }
    return buf.String()
}

const templ = `where={
{{- range $idx,$n := . -}}
    {{if ne $idx 0}},{{end}}"node_name":"{{$n}}"
{{- end -}}
}`

使用strings.Join()

由于其简单性,该解决方案很有趣.我们可以使用strings.Join()加入节点,其中包含静态文本“,”node_name“:”,应用正确的前缀和后缀.

需要注意的一点是:strings.Join()使用内置的copy()函数和一个预先分配的[]字节缓冲区,所以它非常快! “作为一种特殊情况,它(copy()函数)也会将字符串中的字节复制到一片字节.”

func buildJoin(nodes []string) string {
    if len(nodes) == 0 {
        return "where={}"
    }
    return `where={"node_name":"` + strings.Join(nodes,`","node_name":"`) + `"}`
}

基准测试结果

我们将使用以下节点值进行基准测试:

var nodes = []string{"n1","node2","nodethree","fourthNode","n1",}

基准测试代码如下所示:

func BenchmarkOriginal(b *testing.B) {
    for i := 0; i < b.N; i++ {
        buildOriginal(nodes)
    }
}

func BenchmarkBuffer(b *testing.B) {
    for i := 0; i < b.N; i++ {
        buildBuffer(nodes)
    }
}

// ... All the other benchmarking functions look the same

现在的结果是:

BenchmarkOriginal-4               200000             10572 ns/op
BenchmarkBuffer-4                 500000              2914 ns/op
BenchmarkBuffer2-4               1000000              2024 ns/op
BenchmarkBufferTemplate-4          30000             77634 ns/op
BenchmarkJoin-4                  2000000               830 ns/op

一些不足为奇的事实:buildBuffer()比buildOriginal()快3.6倍,而buildBuffer2()(预先计算的大小)比buildBuffer()快30%,因为它不需要重新分配(并复制)内部缓冲.

一些令人惊讶的事实:buildJoin()非常快,甚至比buildBuffer2()快2.4倍(由于只使用了[]字节和copy()).另一方面,buildTemplate()证明非常慢:比buildOriginal()慢7倍.造成这种情况的主要原因是它在引擎盖下使用(必须使用)反射.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读