doudao2954 2018-08-31 19:18
浏览 217
已采纳

我可以用make或new在golang中预填充字符串吗?

I am trying to optimize my stringpad library in Go. So far the only way I have found to fill a string (actually bytes.Buffer) with a known character value (ex. 0 or " ") is with a for loop.

the snippet of code is:

// PadLeft pads string on left side with p, c times
func PadLeft(s string, p string, c int) string {
    var t bytes.Buffer
    if c <= 0 {
        return s
    }
    if len(p) < 1 {
        return s
    }
    for i := 0; i < c; i++ {
        t.WriteString(p)
    }
    t.WriteString(s)
    return t.String()
}

The larger the string pad I believe there is more memory copies of the t buffer. Is there a more elegant way to make a known size buffer with a known value on initialization?

  • 写回答

1条回答 默认 最新

  • dongmibeng5885 2018-08-31 19:45
    关注

    You can only use make() and new() to allocate buffers (byte slices or arrays) that are zeroed. You may use composite literals to obtain slices or arrays that initially contain non-zero values, but you can't describe the initial values dynamically (indices must be constants).

    Take inspiration from the similar but very efficient strings.Repeat() function. It repeats the given string with given count:

    func Repeat(s string, count int) string {
        // Since we cannot return an error on overflow,
        // we should panic if the repeat will generate
        // an overflow.
        // See Issue golang.org/issue/16237
        if count < 0 {
            panic("strings: negative Repeat count")
        } else if count > 0 && len(s)*count/count != len(s) {
            panic("strings: Repeat count causes overflow")
        }
    
        b := make([]byte, len(s)*count)
        bp := copy(b, s)
        for bp < len(b) {
            copy(b[bp:], b[:bp])
            bp *= 2
        }
        return string(b)
    }
    

    strings.Repeat() does a single allocation to obtain a working buffer (which will be a byte slice []byte), and uses the builtin copy() function to copy the repeatable string. One thing noteworthy is that it uses the working copy and attempts to copy the whole of it incrementally, meaning e.g. if the string has already been copied 4 times, copying this buffer will make it 8 times, etc. This will minimize the calls to copy(). Also the solution takes advantage of that copy() can copy bytes from a string without having to convert it to a byte slice.

    What we want is something similar, but we want the result to be prepended to a string.

    We can account for that, simply allocating a buffer that is used inside Repeat() plus the length of the string we're left-padding.

    The result (without checking the count param):

    func PadLeft(s, p string, count int) string {
        ret := make([]byte, len(p)*count+len(s))
    
        b := ret[:len(p)*count]
        bp := copy(b, p)
        for bp < len(b) {
            copy(b[bp:], b[:bp])
            bp *= 2
        }
        copy(ret[len(b):], s)
        return string(ret)
    }
    

    Testing it:

    fmt.Println(PadLeft("aa", "x", 1))
    fmt.Println(PadLeft("aa", "x", 2))
    fmt.Println(PadLeft("abc", "xy", 3))
    

    Output (try it on the Go Playground):

    xaa
    xxaa
    xyxyxyabc
    

    See similar / related question: Is there analog of memset in go?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型