Множественные возвращаемые значения
Одной из необычных особенностей Go является то, что функции и методы могут возвращать несколько значений. Эта форма может быть использована для улучшения пары неуклюжих идиом в программах на C: возвраты внутриполосных ошибок как -1
для EOF
и изменение аргумента, переданного по адресу.
В C ошибка записи сигнализируется отрицательным числом с кодом ошибки скрытым в нестабильном месте. В Go Write
может вернуть число и ошибку, например: "Да, вы написали несколько байтов, но не все, потому что вы заполнили всю память устройства". Сигнатура метода Write
для файлов из пакета os
:
func (file *File) Write(b []byte) (n int, err error)
и как говорится в документации, он возвращает количество записанных байтов и не-nil error
, когда n != len(b)
. Это общепринятый стиль.
Подобный подход избавляет от необходимости передавать указатель на возвращаемое значение для имитации ссылочного параметра. Вот простая функция для захвата числа из позиции в срезе байта, возвращающая число и следующую позицию.
func nextInt(b []byte, i int) (int, int) {
for ; i < len(b) && !isDigit(b[i]); i++ {
}
x := 0
for ; i < len(b) && isDigit(b[i]); i++ {
x = x*10 + int(b[i]) - '0'
}
return x, i
}
Вы можете использовать ее для сканирования чисел во входном срезе b
следующим образом:
for i := 0; i < len(b); {
x, i = nextInt(b, i)
fmt.Println(x)
}
Именованные результирующие параметры
Возвращаемым или результирующим «параметрам» Go функции могут быть присвоены имена и они могут быть использованы как обычные переменные, как и входящие параметры. При именовании они инициализируются нулевыми значениями для своих типов, когда функция начинается; если функция выполняет оператор return
без аргументов текущие значения результирующих параметров используется в качестве возвращаемых значений.
Имена не обязательны, но они могут сделать код короче и понятнее: это документация. Если мы назовем результаты nextInt
, станет очевидно, который из возвращаемых int
который.
func nextInt(b []byte, pos int) (value, nextPos int) {
Поскольку именованные результаты инициализируются и привязываются к неприукрашенному return, они могут упростить, а также уточнить. Вот версия io.ReadFull
, который использует их:
func ReadFull(r Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
return
}
Читайте также:
- Эффективный Go: управляющие структуры, оператор if
- Эффективный Go: повторная декларация и переназначение
- Эффективный Go: цикл for
Комментариев нет:
Отправить комментарий