Комментарии 44
как мне кажется, уж лучше использовать наработанные стереотипы от других языков. Вместо
лучше использовать форму
try errIo, errNet {
// ..........
} catch {
// ..........
}
лучше использовать форму
try {
// ..........
} catch errIo, errNet {
// ..........
}
+4
Ага, и вместо
использовать обычный подход:
И, внезапно, получаем стандартную инструкцию try/catch. Потому что она уже продумана и испытана во многих языках. Но, по какой-то причине, это не go-way.
switch err {
case net.Error1:
doSomethingWithNetError()
case net.Error2:
doSomethingWithNetError()
case io.Error1:
doSomethingWithIoError()
case io.Error2:
doSomethingWithIoError()
}
использовать обычный подход:
try {
// ..........
} catch errNet {
// ..........
} catch errIo {
// ..........
}
И, внезапно, получаем стандартную инструкцию try/catch. Потому что она уже продумана и испытана во многих языках. Но, по какой-то причине, это не go-way.
+4
Не по какой-то, а по вполне определённой — создатели языка верят, что использование исключений приводит к запутанному коду.
+1
как мне кажется, уж лучше использовать наработанные стереотипы от других языков
Если ловить исключения, и делать это так, чтобы было максимально похоже на другие языки — возможно, но смысл конструкции с объявлением переменных сразу после try в том, что там происходит их инициализация. В противном случае мы в catch можем искать переменные, которые не инициализированы — до них просто очередь не дошла.
Ну это, конечно, если не ломать сам подход к обработке ошибок. Если ломать — придётся устроить большой холивар на тему «в какую сторону» и «нужно ли». И мне почему-то кажется, что за «ломать» будут в первую очередь те, кто на Go не пишут, а большинство среди тех, кто будет «против» — использует этот язык ежедневно.
0
Я возможно не совсем понял, но какой смысл в этой заметке, если это не работает? :)
Или это какой-то совет разработчикам языка?
Или это какой-то совет разработчикам языка?
+5
При необходимости на Go легко реализуется поведение, подобное try/catch, при чем без лишнего оверхеда по сравнению с теми языками, где это выделено в отдельную сущность. Но, по причине отсутствия явной поддержки исключений в языке, в Go это реализуется в более многословном виде без синтаксического сиропчика. Но в случае уместности такого подхода это вполне идиоматично и именно это и нужно делать и именно это и делается, в том числе в стандартной библиотеке языка.
Но как показывает многолетняя практика разных языков программирования, наличие инструкций try/catch провоцирует использование этого инструмента везде и всегда, тогда как на самом деле такой подход к обработке ошибок оправдан лишь в небольшом количестве случаев. Именно поэтому эта функциональность выпилена из языка с корнем. Это компромисс, который заставляет иногда реализовывать try/catch в ручную ради искоренения тотального засилья трай-блоков во всем коде.
Это сделано умышленно и это ни когда не поменяется. И эта особенность не преподносится как идеальное решение, это не преподносится как эталон для подражания, это не преподносится как ноу-хау. Это сделано из соображений циничного прагматизма. И как у любого компромисса, эта особенность языка имеет и слабые и сильные стороны, но в целом этот подход приводит к более качественному и более поддерживаемому коду.
Но как показывает многолетняя практика разных языков программирования, наличие инструкций try/catch провоцирует использование этого инструмента везде и всегда, тогда как на самом деле такой подход к обработке ошибок оправдан лишь в небольшом количестве случаев. Именно поэтому эта функциональность выпилена из языка с корнем. Это компромисс, который заставляет иногда реализовывать try/catch в ручную ради искоренения тотального засилья трай-блоков во всем коде.
Это сделано умышленно и это ни когда не поменяется. И эта особенность не преподносится как идеальное решение, это не преподносится как эталон для подражания, это не преподносится как ноу-хау. Это сделано из соображений циничного прагматизма. И как у любого компромисса, эта особенность языка имеет и слабые и сильные стороны, но в целом этот подход приводит к более качественному и более поддерживаемому коду.
+3
Очень интересно было бы посмотреть на реализацию try/catch в Go руками. Пишу без сарказма, действительно интересно.
Мне на ум приходит только panic/defer/recovery, но этот подход требует создания оберток функций для блоков try/catch, что сильно усложняет код и портит его обозримость. Не говоря уж о том, что это неправильный подход для Go.
Мне на ум приходит только panic/defer/recovery, но этот подход требует создания оберток функций для блоков try/catch, что сильно усложняет код и портит его обозримость. Не говоря уж о том, что это неправильный подход для Go.
0
Главный вопрос в ловле panic — производительность. Мне кажется, она тут страдает.
+1
Почему она не страдает в случае try…catch, но страдает в случае panic…defer?
0
> Почему она не страдает в случае try…catch
Очень даже страдает. В той же Java, например.
Очень даже страдает. В той же Java, например.
+1
Немного потеоритезирую, но в случае имплементации моей версии try...catch компилятор после каждого присвоения нового значения указанным после try переменным типа error — сразу после того, как записал их значение (коим является 64-битный адрес объекта ошибки) в память, но до того, как вытеснил это значение из регистра — просто смотрит, является ли значение в регистре отличным от нуля. Если да — следует простой переход в блок catch, а все нужные значения при этом уже находятся на своих местах. Никаких других накладных расходов, вроде, не предвидится. Не думаю, что в данном варианте логики производительность сильно пострадает. Всего лишь одна проверка регистра на 0.
Полноценное исключение, насколько я его понимаю, является гораздо более масштабным мероприятием.
Полноценное исключение, насколько я его понимаю, является гораздо более масштабным мероприятием.
+1
> try err {
> go func() {
> err = MyCoolFunc()
> } ()
> } catch {
>
> }
как будет работать такой код?
> go func() {
> err = MyCoolFunc()
> } ()
> } catch {
>
> }
как будет работать такой код?
0
Хороший вопрос.
Я бы не ловил в данном случае. То есть catch ловит только внутри текущей goroutine.
Я бы не ловил в данном случае. То есть catch ловит только внутри текущей goroutine.
0
ну то есть мало проверить на nil надо ещё тогда проверить кто его туда записал, значит надо записать куда-то кто его туда записал и так далее
+1
А как-же замыкания?
0
Вы в контексте мою фразу прочитайте.
0
Блоки try/cath выглядят весьма уродливо. Они запутывают структуру кода и смешивают обработку ошибок с нормальной обработкой. Что мешает сделать как то так?
if err := client.Set("Fatal", " ", 0).Err(); err != nil {
log.Print(err)
}
0
с одной стороны да, но пример из статьи так не записать без явного обявления переменных customVar и err
0
т.е. вот это менее уродливо?
client.Set(«Fatal», " ", 0).Err()
-1
это redis либа если что. Где
client — индикаторный соединения
Fatal — имя ключа
" " — содержание.
Ну а если не нравиться можно написать свою либу. Благодаря Go я это могу сделать за 30 минут просто изучив команды редиса.
client — индикаторный соединения
Fatal — имя ключа
" " — содержание.
Ну а если не нравиться можно написать свою либу. Благодаря Go я это могу сделать за 30 минут просто изучив команды редиса.
-1
менее уродливо чем что?
0
try/cath я полагаю
0
согласен! Пример не удачен. Вот обработка ошибок бд (не кривая либа с гитхаба, а коробочная)
Вы тупо вместо трех этажных конструкций всё делаете сразу в if.
if rows, err := DB.Query("SELECT * FROM users WHERE login=?", login);err !=nil {
log.Fatal(err)
}
Вы тупо вместо трех этажных конструкций всё делаете сразу в if.
0
ну это не корректно с try/catch тут только if,err надо сравнивать, остальное дизайн библиотеки (конкретно эта возвращает чуть больше чем err)
то есть
> if err := client.Set(«Fatal», " ", 0); err != nil {
> log.Print(err)
> }
vs
> try {
> client.Set(«Fatal», " ", 0)
> } catch (Exception e){
> log.Println(e.getMessage())
> }
в этом случае вариант с if явно короче.
по поводу ошибки как значения против исключений можно холиварить много, но не надо тащить в Go практики работы с исключениями.
то есть
> if err := client.Set(«Fatal», " ", 0); err != nil {
> log.Print(err)
> }
vs
> try {
> client.Set(«Fatal», " ", 0)
> } catch (Exception e){
> log.Println(e.getMessage())
> }
в этом случае вариант с if явно короче.
по поводу ошибки как значения против исключений можно холиварить много, но не надо тащить в Go практики работы с исключениями.
+1
Адско плюсую. Правда кармы не хватает))
-2
Вся суть обработки исключений в том, что не надо проверять результат после каждого библиотечного вызова.
По моему опыту, большинство функций вообще обходятся без try. Обработка ошибок не видна и не засоряет код.
В try заворачивается весь main или вся транзакция, или обработка взаимодействия с одним подключением (отвалилось — залогировали и забыли). В тех случаях, когда ошибки ожидаются, нужно вызывать фунции со статусом-результатом (TryParse вместо Parse, TryGetValue вместо обращения к Dictionary по индексу). Да, методов в библиотеках становится больше, зато писать код быстрее.
Go не даёт выбора.
По моему опыту, большинство функций вообще обходятся без try. Обработка ошибок не видна и не засоряет код.
В try заворачивается весь main или вся транзакция, или обработка взаимодействия с одним подключением (отвалилось — залогировали и забыли). В тех случаях, когда ошибки ожидаются, нужно вызывать фунции со статусом-результатом (TryParse вместо Parse, TryGetValue вместо обращения к Dictionary по индексу). Да, методов в библиотеках становится больше, зато писать код быстрее.
Go не даёт выбора.
+3
> По моему опыту, большинство функций вообще обходятся без try. Обработка ошибок не видна и не засоряет код.
Вот это именно то к чему склоняют исключения — генерировать ошибки, но не обрабатывать ошибки, а просто поймать их где-то в общем для всего приложения месте.
> Go не даёт выбора.
а ещё выбора не дает Rust
Вот это именно то к чему склоняют исключения — генерировать ошибки, но не обрабатывать ошибки, а просто поймать их где-то в общем для всего приложения месте.
> Go не даёт выбора.
а ещё выбора не дает Rust
-1
Вот это именно то к чему склоняют исключения
Они склоняют, а мы не поддаёмся. Исключения не должны быть единственным способом передачи ошибки, как я писал выше. Программист должен взвешенно выбрать, что использовать.
Конструкции типа
try { client.Set(«Fatal», " ", 0); } catch (Exception e)
это антипаттерн, не надо их приводить в пример.0
Я не его приводил в пример, а просто написал эквивалентный вариант по Go коду.
В Rust и Go на уровне дизайна разделены случаи ошибок и исключительных ситуаций, зачем пытаться делать ещё одну сущность и собрать их вместе?
Как мне писать в этом случае код работайщий со сторонним кодом, когда у меня одна функция возвращает error, а вторая исключения, stack trace будет формироваться в обоих случаях? почему в с# это сделано только для некоторых классов но не для всех (уж не потому, что иметь 2х методов это пзцд)?
Почему в статьях про Rust — http://habrahabr.ru/post/242269/ большинство говорят, что да это классно, а в статьях про Go — как там могли придумать вообще, верните мои исключения
В Rust и Go на уровне дизайна разделены случаи ошибок и исключительных ситуаций, зачем пытаться делать ещё одну сущность и собрать их вместе?
Как мне писать в этом случае код работайщий со сторонним кодом, когда у меня одна функция возвращает error, а вторая исключения, stack trace будет формироваться в обоих случаях? почему в с# это сделано только для некоторых классов но не для всех (уж не потому, что иметь 2х методов это пзцд)?
Почему в статьях про Rust — http://habrahabr.ru/post/242269/ большинство говорят, что да это классно, а в статьях про Go — как там могли придумать вообще, верните мои исключения
0
Я не его приводил в пример, а просто написал эквивалентный вариант по Go коду.
В принципе плохой пример. Ошибка логируется, а программа продолжает как ни в чём не бывало и падает на следующей строке из-за того, что предыдущий оператор не выполнился.
Хороший пример — это вернуть err в вызывающую ф-цию.
Тогда аналог на c#/java вообще бы не содержал бы никаких try/catch, ни одного лишнего символа в коде на обработку ошибок. Исключение прозрачно ушло бы наверх.
Как мне писать в этом случае код работайщий со сторонним кодом, когда у меня одна функция возвращает error, а вторая исключения, stack trace будет формироваться в обоих случаях?
На нагрузку на стек никак не влияет наличие try/catch, ведь trace надо будет собрать в любом случае, если где-то в глубине дерева вызовов случится panic.
0
Go не даёт выбора.
Для указанного случая — как раз таки даёт «из коробки». Только вместо try в main или транзакцию снизу кидается panic, которую наверху ловят через defer/recover.
0
Что то мне это напоминает, ах да это же java а именно try-with-resources
Ваш подход очень похож. И не так уж плох.
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
System.out.println(---);
}
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
}
Ваш подход очень похож. И не так уж плох.
0
НЛО прилетело и опубликовало эту надпись здесь
Этим можно пользоваться, если все нижележащие функции возвращают ошибку.
Как только мы написали foo!, наша функция начинает кидать исключение и к ней этот подход перестаёт работать.
Конечно, можно ловить исключение и преобразовывать его в ошибку, но программист никогда не будет уверен, то с чем он сейчас работает, не кидает ли скрытые исключения, просаживая производительность.
Как только мы написали foo!, наша функция начинает кидать исключение и к ней этот подход перестаёт работать.
Конечно, можно ловить исключение и преобразовывать его в ошибку, но программист никогда не будет уверен, то с чем он сейчас работает, не кидает ли скрытые исключения, просаживая производительность.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Идея по обработке ошибок в Go