Мне кажется, Google альтернативы исключениям
- GO: многозначный возврат "return val, err;"
- GO, С++: проверка nil (раннее возвращение)
- GO, С++: "обрабатывать проклятую ошибку" (мой термин)
-
С++: assert (выражение)
-
GO: defer/panic/recover - это языковые функции, добавленные после запроса этого вопроса
Является ли многозначное возвращение полезным, чтобы действовать как альтернатива? Почему "утверждает" рассматриваемые альтернативы? Думает ли Google, что это O.K. если программа останавливается, если возникает ошибка, которая не обрабатывается правильно?
Эффективное GO: Множественные значения возврата
Одна из необычных особенностей Go заключается в том, что функции и методы могут возвращать несколько значений. Это можно использовать для улучшения пары неуклюжих идиом в программах на языке C: внутриполосные ошибки (например, -1 для EOF) и изменение аргумента.
В C ошибка записи сигнализируется отрицательный счетчик с кодом ошибки выделяется в нестабильном месте. В Go, Write может возвращать счетчик и error: "Да, вы написали несколько байтов, но не все из-за того, что вы заполнили устройство". Подпись * File.Write в пакете os:
func (file *File) Write(b []byte) (n int, err Error)
и, как говорится в документации, это возвращает количество записанных байтов и non-nil Error при n!= len (b). Это общий стиль; см. раздел об обработке ошибок для примеры.
Эффективное GO: Именованные параметры результата
Возврат или результат "параметров" Функция Go может иметь имена и используются как обычные переменные, так же как и входящие параметры. Когда он называется, они инициализируются нулем значения для их типов, когда функция начинается; если функция выполняет оператор возврата без аргументы, текущие значения параметры результата используются как возвращаемые значения.
Имена не являются обязательными, но они может сделать код короче и понятнее: это документация. Если мы назовем результаты nextInt становятся очевидными который возвратил int, который.
func nextInt(b []byte, pos int) (value, nextPos int) {
Поскольку именованные результаты инициализируются и привязаны к без возврата, они могут а также уточнить. Здесь версия io.ReadFull, который их хорошо использует:
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int;
nr, err = r.Read(buf);
n += nr;
buf = buf[nr:len(buf)];
}
return;
}
Исключения подобная история. Был предложен ряд проектов для исключений, но каждый из них значительно усложняет язык и время выполнения. По самой своей природе исключения включают в себя функции и, возможно, даже гортаны; они имеют широкомасштабные последствия. Существует также озабоченность по поводу того эффекта, который они могут оказать на библиотеки. Они по определению являются исключительными, но опыт работы с другими языками, которые их поддерживают, показывают, что они оказывают глубокое влияние на спецификацию библиотеки и интерфейса. Было бы неплохо найти дизайн, который позволит им быть действительно исключительным, не поощряя распространенные ошибки превращаться в специальный поток управления, который требует от каждого программиста компенсации.
Подобно дженерикам, исключения остаются открытой проблемой.
Руководство по стилю Google С++: Исключения
Решение:
С их стороны преимущества использования исключения перевешивают издержки, особенно в новых проектах. Однако, для существующего кода, введение исключения имеют последствия для всех зависимый код. Если исключения могут быть распространялся за рамки нового проекта, он также становится проблематичным для интеграции новый проект в существующий исключающий код. Потому что большинство существующий код на С++ в Google не подготовленный к устранению исключений, он сравнительно трудно принять новый код, который генерирует исключения.
Учитывая, что существующий код Google а не исключения, использование исключений несколько больше чем затраты в новом проекте. Процесс конверсии будет медленным и подвержены ошибкам. Мы не считаем, что доступных альтернатив исключения, такие как коды ошибок и утверждения, представляют значительный бремя.
Наш совет против использования исключений не основывается на философских или моральные основания, но практические. Потому что мы хотели бы использовать наши проекты с открытым исходным кодом в Google и это трудно сделать, если эти проекты используют исключения, нам нужно рекомендовать исключение из Google проекты с открытым исходным кодом. вещи вероятно, были бы разными, если бы мы делать все сначала с нуля.
GO: Отложить, Паника и Восстановление
Операторы Defer позволяют нам думать о закрытии каждого файла сразу после его открытия, гарантируя, что независимо от количества операторов возврата в функции файлы будут закрыты.
Поведение операторов отсрочки является простым и предсказуемым. Существует три простых правила:
1. Аргументы отложенной функции оцениваются, когда вычисляется оператор defer.
В этом примере выражение "i" оценивается при отсрочке вызова Println. Отложенный вызов будет печатать "0" после возвращения функции.
func a() { i := 0 defer fmt.Println(i) i++ return }
2. Отложенные вызовы функций выполняются в порядке "Последний вход в первый выход" после возвращения внешней функции. Эта функция печатает "3210":
func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } }
3. Отложенные функции могут читать и присваивать возвращаемой функции с именами возвращаемых значений.
В этом примере отложенная функция увеличивает возвращаемое значение я после возвращения функции окружения. Таким образом, эта функция возвращает 2:
func c() (i int) { defer func() { i++ }() return 1 }
Это удобно для изменения возвращаемого значения ошибки для функции; мы вскоре увидим пример этого.
Panic - это встроенная функция, которая останавливает обычный поток управления и начинает паниковать. Когда функция F вызывает панику, выполнение F останавливается, любые отложенные функции в F выполняются нормально, и то F возвращается к своему вызывающему абоненту. Для вызывающего абонента F затем ведет себя как призыв к панике. Процесс продолжается до стека до тех пор, пока все функции в текущем goroutine не вернутся, и в этот момент программа выйдет из строя. Паники могут быть инициированы путем прямого вызова паники. Они также могут быть вызваны ошибками во время выполнения, такими как доступ к массивам вне пределов.
Recover - это встроенная функция, которая восстанавливает управление паникой goroutine. Восстановление полезно только в отложенных функциях. Во время нормального выполнения вызов для восстановления возвращает нуль и не имеет другого эффекта. Если текущий goroutine впадает в панику, вызов восстанавливает значение, указанное для паники, и возобновляет нормальное выполнение.
Вот пример программы, демонстрирующей механику паники и отсрочки:
<snip>
Для реального примера паники и восстановления см. пакет json из стандартной библиотеки Go. Он декодирует JSON-кодированные данные с набором рекурсивных функций. Когда встречается некорректный JSON, парсер вызывает панику, чтобы развернуть стек до вызова функции верхнего уровня, который восстанавливается из паники и возвращает соответствующее значение ошибки (см. Функции "error" и "unmarshal" в decode.go), Аналогичный пример этого метода приведен в процедуре компиляции пакета regexp. Соглашение в библиотеках Go заключается в том, что даже если пакет использует панику внутри, внешний API все еще содержит явные значения возвращаемых ошибок.
Другие использования отсрочки (помимо примера file.Close(), приведенного выше) включают освобождение мьютекса:
mu.Lock() defer mu.Unlock