вторник, 22 января 2019 г.

Эффективный Go: функции

Множественные возвращаемые значения

Одной из необычных особенностей 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
}


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


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

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