Срезы оборачивают массивы, чтобы дать более общий, мощный и удобный интерфейс с последовательностями данных. За исключением предметов с явным измерением, такие как матрицы преобразования, большая часть программирования массивов в Go делается со срезами, а не с простыми массивами.
Срезы содержат ссылки на базовый массив, и если вы назначите один срез к другому, оба будут ссылаться на один и тот же массив. Если функция принимает аргумент срез, изменения, которые она вносит в элементы среза, будут видны вызывающей стороне, аналогично передаче указателя на базовый массив. Read
функция поэтому может принимать аргумент срез, а не указатель и счет; длина внутри среза устанавливает верхний предел того, сколько данных для чтения. Вот сигнатура метода Read
типа File
в пакете os
:
func (f *File) Read(buf []byte) (n int, err error)
Метод возвращает количество прочитанных байтов и значение ошибки, если она есть. Для считывания первых 32 байт большего буфера buf
, сделаем срез буфера.
n, err := f.Read(buf[0:32])
Такая нарезка является распространенной и эффективной. Фактически, оставляя эффективность в стороне на данный момент, следующий фрагмент также будет читать первые 32 байта буфера.
var n int
var err error
for i := 0; i < 32; i++ {
nbytes, e := f.Read(buf[i:i+1]) // Читаем один байт.
if nbytes == 0 || e != nil {
err = e
break
}
n += nbytes
}
Длина среза может быть изменена до тех пор, пока он все еще вписывается в пределы базового массива; просто назначьте его на срез самого себя. Емкость среза, доступная встроенной функции cap
, сообщает максимальную длину среза, которую можно предполагать. В следующем примере представлена функция для добавления данных в срез. Если данные превышает емкость, срез перераспределяется. Полученный срез возвращается. Функция использует тот факт, что len
и cap
являются законными применительно к nil
и возвращает 0 в этом случае.
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
может изменять элементы slice
, сам срез (структура данных времени выполнения, содержащая указатель, длину и емкость) передается по значению.
Идея добавления к срезу очень полезна, и используется встроенной функцией append
.
Читайте также:
- Эффективный Go: данные, аллокация с помощью make
- Основы Go: массивы (arrays)
- Основы Go: срезы (slices)
Комментариев нет:
Отправить комментарий