Go:从[]字节转换为字符串的开销,反之亦然

Ala*_*air 6 string go

我似乎总是一遍又一遍地将字符串转换为[] byte到string.这有很多开销吗?有没有更好的办法?

例如,这是一个接受UTF8字符串,规范化,删除重音,然后将特殊字符转换为ASCII等效字符的函数:

var transliterations = map[rune]string{'Æ':"AE",'Ð':"D",'?':"L",'Ø':"OE",'Þ':"Th",'ß':"ss",'æ':"ae",'ð':"d",'?':"l",'ø':"oe",'þ':"th",'Œ':"OE",'œ':"oe"}
func RemoveAccents(s string) string {
    b := make([]byte, len(s))
    t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
    _, _, e := t.Transform(b, []byte(s), true)
    if e != nil { panic(e) }
    r := string(b)

    var f bytes.Buffer
    for _, c := range r {
        temp := rune(c)
        if val, ok := transliterations[temp]; ok {
            f.WriteString(val)
        } else {
            f.WriteRune(temp)
        }
    }
    return f.String()
}
Run Code Online (Sandbox Code Playgroud)

所以我开始使用字符串,因为这是我得到的,然后我将它转换为字节数组,然后返回到字符串,然后再转换为字节数组,然后再转换回字符串.当然这是不必要的,但我无法弄清楚如何不这样做..?它是否真的有很多开销,或者我不必担心过度转换会减慢速度?

(如果有人有时间我还没弄清楚bytes.Buffer实际上是如何工作的,那么初始化一个字符串大小2 倍的缓冲区会不会更好,这是返回值的最大输出大小?)

pet*_*rSO 4

在 Go 中,strings 是不可变的,因此任何更改都会创建一个新字符串。作为一般规则,从 a 转换string为 abyterune切片一次,然后再转换回string一次。为了避免重新分配,对于小型和暂时的分配,如果您不知道确切的数字,请过度分配以提供安全裕度。

\n\n

例如,

\n\n
package main\n\nimport (\n    "bytes"\n    "fmt"\n    "unicode"\n    "unicode/utf8"\n\n    "code.google.com/p/go.text/transform"\n    "code.google.com/p/go.text/unicode/norm"\n)\n\nvar isMn = func(r rune) bool {\n    return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks\n}\n\nvar transliterations = map[rune]string{\n    \'\xc3\x86\': "AE", \'\xc3\x90\': "D", \'\xc5\x81\': "L", \'\xc3\x98\': "OE", \'\xc3\x9e\': "Th",\n    \'\xc3\x9f\': "ss", \'\xc3\xa6\': "ae", \'\xc3\xb0\': "d", \'\xc5\x82\': "l", \'\xc3\xb8\': "oe",\n    \'\xc3\xbe\': "th", \'\xc5\x92\': "OE", \'\xc5\x93\': "oe",\n}\n\nfunc RemoveAccents(b []byte) ([]byte, error) {\n    mnBuf := make([]byte, len(b)*125/100)\n    t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)\n    n, _, err := t.Transform(mnBuf, b, true)\n    if err != nil {\n        return nil, err\n    }\n    mnBuf = mnBuf[:n]\n    tlBuf := bytes.NewBuffer(make([]byte, 0, len(mnBuf)*125/100))\n    for i, w := 0, 0; i < len(mnBuf); i += w {\n        r, width := utf8.DecodeRune(mnBuf[i:])\n        if s, ok := transliterations[r]; ok {\n            tlBuf.WriteString(s)\n        } else {\n            tlBuf.WriteRune(r)\n        }\n        w = width\n    }\n    return tlBuf.Bytes(), nil\n}\n\nfunc main() {\n    in := "test string\xc3\x9f"\n    fmt.Println(in)\n    inBytes := []byte(in)\n    outBytes, err := RemoveAccents(inBytes)\n    if err != nil {\n        fmt.Println(err)\n    }\n    out := string(outBytes)\n    fmt.Println(out)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
test string\xc3\x9f\ntest stringss\n
Run Code Online (Sandbox Code Playgroud)\n