суббота, 26 января 2019 г.

Эффективный Go: встроенная функция append

В посте о срезах мы написали функцию Append для добавления элементов в срез:

func Append(slice, data []byte) []byte {
    l := len(slice)
    if l + len(data) > cap(slice) {  // реаллоцируем
        // Аллоцирем в двойном размере требуемого, 
        // для будущего роста.
        newSlice := make([]byte, (l+len(data))*2)
        // copy функция предопределена 
        // и работает для любого типа среза.
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:l+len(data)]
    copy(slice[l:], data)
    return slice
}

Сигнатура append отличается от нашей пользовательской функции Append выше. Схематически:

func append(slice []T, elements ...T) []T

где T является заполнителем для любого данного типа. Вы не можете на самом деле написать функцию в Go, где тип T определяется вызывающим абонентом. Вот почему append встроен: он уждается в поддержке со стороны компилятора.

Что append делает - это добавляет элементы в конец среза и возвращает результат. Результат нужно вернуть потому что, как и в случае с нашим рукописным Append, основной массив может измениться. Вот простой пример:

x := []int{1,2,3}
x = append(x, 4, 5, 6)
fmt.Println(x)

печатает [1 2 3 4 5 6]. Таким образом, append работает немного похоже на Printf, собирая произвольное число аргументов.

Но что, если мы хотим сделать то, что делает наш Append, и добавить срез в срез? Легко: используйте ... при вызове места, как мы это делали при вызове Output выше. Следующий пример выдает результат, идентичный приведенному выше.

x := []int{1,2,3}
y := []int{4,5,6}
x = append(x, y...)
fmt.Println(x)

Без этого ... он не скомпилируется, потому что типы были бы неправильные; y не относится к типу int.


Читайте также:


Комментариев нет:

Отправить комментарий