首页 > 解决方案 > 获取 Golang 字符串的最后一个 X 字符哪个更好?

问题描述

当我有字符串“hogemogehogemogehogemoge世界世界世界”时,哪个代码更适合通过避免内存分配来获得最后一个符文?

关于获取 Golang String 的最后一个 X 字符也有类似的问题。

如何获取 Golang 字符串的最后 X 个字符?

如果我只想获得最后一个符文,我想确定哪个是首选,而不需要任何额外的操作。

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    // which is more better for memory allocation?
    s := "hogemogehogemogehogemoge世界世界世界a"
    getLastRune(s, 3)
    getLastRune2(s, 3)
}

func getLastRune(s string, c int) {
    // DecodeLastRuneInString
    j := len(s)
    for i := 0; i < c && j > 0; i++ {
        _, size := utf8.DecodeLastRuneInString(s[:j])
        j -= size
    }
    lastByRune := s[j:]
    fmt.Println(lastByRune)
}

func getLastRune2(s string, c int) {
    // string -> []rune
    r := []rune(s)
    lastByRune := string(r[len(r)-c:])
    fmt.Println(lastByRune)
}

世界a

世界a

标签: stringgoutf-8rune

解决方案


每当性能和分配成为问题时,您都应该运行基准测试。

首先让我们修改您的函数以不打印而是返回结果:

func getLastRune(s string, c int) string {
    j := len(s)
    for i := 0; i < c && j > 0; i++ {
        _, size := utf8.DecodeLastRuneInString(s[:j])
        j -= size
    }
    return s[j:]
}

func getLastRune2(s string, c int) string {
    r := []rune(s)
    if c > len(r) {
        c = len(r)
    }
    return string(r[len(r)-c:])
}

和基准功能:

var s = "hogemogehogemogehogemoge世界世界世界a"

func BenchmarkGetLastRune(b *testing.B) {
    for i := 0; i < b.N; i++ {
        getLastRune(s, 3)
    }
}

func BenchmarkGetLastRune2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        getLastRune2(s, 3)
    }
}

运行它们:

go test -bench . -benchmem

结果:

BenchmarkGetLastRune-4     30000000     36.9 ns/op     0 B/op    0 allocs/op
BenchmarkGetLastRune2-4    10000000    165 ns/op       0 B/op    0 allocs/op

getLastRune()快了4 倍以上。他们都没有进行任何分配,但这是由于编译器优化(将 a 转换string[]rune和返回通常需要分配)。

如果我们在禁用优化的情况下运行基准测试:

go test -gcflags '-N -l' -bench . -benchmem

结果:

BenchmarkGetLastRune-4     30000000    46.2 ns/op      0 B/op    0 allocs/op
BenchmarkGetLastRune2-4    10000000   197 ns/op       16 B/op    1 allocs/op

编译器优化与否,getLastRune()显然是赢家。


推荐阅读