Как выбрать сигнатуру функции reverse в Go и какие факторы влияют на выбор
Что проверяют
Умеете ли вы проектировать API функции, а не только написать цикл с двумя индексами. Сигнатура отвечает на три вопроса: меняет ли функция вход, для каких типов она работает и сколько памяти выделяет. Следом обычно просят сделать то же самое для строки.
Как отвечать
Начните с главного решения: разворот на месте или новая копия.
- на месте:
func Reverse[S ~[]E, E any](s S). Ничего не возвращает, и это сознательный сигнал вызывающему: срез изменён. Ноль аллокаций, два индекса идут навстречу и меняют элементы местами. Ровно так устроенаslices.Reverseиз стандартной библиотеки (Go 1.21+); - копия:
func Reversed[E any](s []E) []E. Вход не трогается, зато одна аллокация наlen(s)элементов. Нужна, когда исходный срез читают другие части программы; - ограничение
~[]E: позволяет передать именованный тип вродеtype IDs []intи получить обратно тот же тип, а не голый[]int; - строка:
func ReverseString(s string) string. Строки неизменяемы, поэтому результат только новая строка. Разворачивать нужно по рунам через[]rune(s), а не по байтам, иначе многобайтовые символы UTF-8 превратятся в мусор.
Хорошо добавить, что иногда разворот не нужен вовсе: для обхода с конца хватит цикла от len(s)-1 или итератора slices.Backward (Go 1.23+), который ничего не копирует.
Где спотыкаются
Разворачивают на месте и при этом возвращают тот же срез. Вызывающий думает, что получил копию, и не ждёт, что исходные данные тоже поменялись: оба среза смотрят в один массив.
Разворачивают строку по байтам, и кириллица ломается. А на вопрос про эмодзи и буквы с диакритикой не знают, что даже []rune их разбивает: для таких случаев нужна сегментация по графемам.
Пишут сигнатуру с []interface{} ради универсальности. []int в неё не передать без ручного копирования, а дженерики в языке есть с версии 1.18.