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?

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

报告相同问题?

悬赏问题

  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂