
Одной из частых операций может оказаться объединения(concatenation) строк, есть много библиотек для решения задач, мы рассмотрим несколько самых распространенных примеров.
В стандартной библиотеке fmt
есть метод Sprintf(format string, a ...interface{}) string
в качестве первого аргумента он принимает формат, в нашем случае это просто %s %s
для двух строк. Также есть метод strings.Join
, тут все просто slice строк и разделитель. Еще можно использовать тип bytes.Buffer
с его методами WriteString
. Ну и не забываем про string+" "+ string"
.
Запустим для всего этого benchmark для 100 строк, результат для него будет такой
BenchmarkSfmt-4 100000 12207 ns/op 4705 B/op 102 allocs/op BenchmarkBuff-4 500000 2516 ns/op 6928 B/op 7 allocs/op BenchmarkJoin-4 1000000 1041 ns/op 1792 B/op 1 allocs/op BenchmarkConc100-4 1000000 1367 ns/op 1792 B/op 1 allocs/op
Сразу видно что fmt.Sprintf
меньше всего для этого подходит, он скорее предназначен когда нам надо больше чем просто объединить строки, с его возможностями можете ознакомится в документации. У него есть также аналоги как например log.Printf
,fmt.Errorf
и тп. Buffer почти в двое проигрывает специализированным решениям, там прямая зависимость от строк , к примеру пустой срез будет иметь такой результат
BenchmarkBuff-4 3000000 405 ns/op 0 B/op 0 allocs/op BenchmarkJoin-4 2000000 787 ns/op 0 B/op 0 allocs/op BenchmarkConc100-4 10000000 134 ns/op 0 B/op 0 allocs/op
а при длине строки в 322 символа
BenchmarkBuff-4 100000 15442 ns/op 125088 B/op 9 allocs/op BenchmarkJoin-4 300000 4451 ns/op 32768 B/op 1 allocs/op BenchmarkConc100-4 300000 4497 ns/op 32768 B/op 1 allocs/op
Если вам нужно объединить строки то используйте +
или strings.Join
. Не используете сложение строк в foreach иначе получите результат сравнимый с Sprintf
BenchmarkFor100-4 100000 14175 ns/op 84848 B/op 99 allocs/op BenchmarkConc100-4 1000000 1328 ns/op 1792 B/op 1 allocs/op
А что если нам нужно сложить не только строки? Для этого надо будет преобразовать типы в строку и точна также сложить, есть пакет strconv
мы будем использовать методы FormatFloat
и Itoa
BenchmarkIfmt-4 100000 12045 ns/op 4289 B/op 102 allocs/op BenchmarkFfmt-4 100000 23098 ns/op 4289 B/op 102 allocs/op BenchmarkJoinInt-4 200000 5824 ns/op 5248 B/op 101 allocs/op BenchmarkJoinFloat-4 100000 19269 ns/op 8448 B/op 201 allocs/op BenchmarkConc100Int-4 200000 6017 ns/op 5248 B/op 101 allocs/op BenchmarkConc100Float-4 100000 18470 ns/op 8448 B/op 201 allocs/op
Тут думаю понятно что выигрыша мы на типе float вообще не получаем, но учитывайте что используются аргументы 'g', -1, 64
.
Выводы
Надеюсь вы перестанете везде использовать методы fmt.Sprintf("err: %s, message: %s", err,message)"
да возможно они более читабельные, или если вас не устраивает использование strings.Join([]string{"err:",err.Error(),"message:",message}, "")
можно сделать в проекте func join(in ...string) string
. По поводу вывода строковой информации о других типов тут уже все зависит от задачи, если будет float или смешанный вариант то я наверное предпочту читабельный код. Если вы для логов делаете вывод то возможно стоит обратить внимание на пакет go.uber.org/zap
там к примеру есть удобные методы SugaredLogger.Warnw
которые позволяют использовать основные типы, и как бонус искать потом по этим полям если вы используете json. Данная статья не последняя инстанция, если у вас есть свои выводы подкрепленные Benchmark
, оставляйте ссылку на gist, уверен будет интересно всем. Все основные результаты можно посмотреть на github.