Вы можете использовать только make()
и new()
для выделения буферов (байтовых срезов или массивов), которые обнуляются. Вы можете использовать составные литералы для получения срезов или массивов, которые изначально содержат ненулевые значения, но вы не можете описать начальные значения динамически (индексы должны быть константами).
Вдохновитесь схожей, но очень эффективной strings.Repeat()
функцией. Повторяет данную строку с указанным количеством:
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()
выполняет однократное распределение для получения рабочего буфера (который будет срезом байтов []byte
) и использует встроенную функцию copy()
для копирования повторяемой строки. Следует отметить, что он использует рабочую копию и пытается копировать ее целиком, например, например. если строка уже была скопирована 4 раза, копирование этого буфера сделает его 8 раз и т. д. Это сведет к минимуму вызовы на copy()
. Кроме того, решение использует то преимущество, что copy()
может копировать байты из string
без необходимости преобразования его в фрагмент байта.
Нам нужно нечто похожее, но мы хотим, чтобы результат был добавлен к строке.
Мы можем объяснить это, просто выделив буфер, который используется внутри Repeat()
плюс длину строки, которую мы заполняем слева.
Результат (без проверки параметра count
):
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)
}
Тестирование:
fmt.Println(PadLeft("aa", "x", 1))
fmt.Println(PadLeft("aa", "x", 2))
fmt.Println(PadLeft("abc", "xy", 3))
Вывод (попробуйте на Go Playground ):
xaa
xxaa
xyxyxyabc
См. Аналогичный / связанный вопрос: Есть ли аналог go memset в go?