Мех
Я работал над проектом, который должен запускаться как небольшой код. Я занимаюсь Си с 1980 года и написал немало коммерческих пакетов на C, C ++, Objective-C и их сочетаниях.
Но после нескольких десятилетий работы с Java и другими управляемыми языками я больше не хочу думать об управлении памятью.
Плюс, проект связан с Docker, и большая часть экосистемы Docker находится на Go . Итак, я решил сделать проект в Go.
Вот мои мысли о «около недели в».
Комфортный
Мне потребовалось много времени, чтобы прогнать Scala и даже получить идиомы Clojure . Я вырос на языке C-ish, и функциональные языки все еще требуют определенных усилий, чтобы понять мотивацию идиом.
Не так с Go. Go — очень, очень удобный язык для меня. Я полностью понимаю это. Я полностью понимаю большинство вариантов дизайна. Я чувствую себя довольно опытным с Go. Ура!
Добро
Есть несколько очень хороших частей Go.
Управляемая память
Управляемая память — первая. Исходя из C / C ++ / ObjC-lang, не нужно думать о malloc / free, подсчете ссылок и т. Д. — это просто здорово. Управляемая память была для меня первым делом, когда я начал программировать на Java 20 лет назад. Иди получил это право.
Интерфейсы
Перейти получить баланс с интерфейсами. Это намного лучше, чем подход C ++. На протяжении многих лет мне действительно нравилась структурная типизация по сравнению с номинальной. Интерфейсы являются структурными типами, и они работают очень хорошо.
Кроме того, наличие необработанных данных (например, int64
), которые повышаются до данных плюс информация о типе, является очень ловкой системой, которая позорит бокс на JVM.
Goroutines
Возможно, лучшая часть Go — это Goroutines, он же CSP . Облегченные потоки в сочетании с очень четко определенным механизмом передачи данных между потоками — это просто потрясающе. Я имею в виду, действительно, действительно здорово.
Написание многопоточного кода на Go очень и очень просто… до тех пор, пока вы не измените данные в сообщениях.
Делать вещи по умолчанию правильно
Go самоуверенно относится к тому, где вы размещаете файлы, и, пока вы размещаете файлы в нужном месте, нет необходимости make
файлы или создавать систему за пределами Go.
Возможность ссылаться на зависимости по URL-адресу и выполнять извлечение зависимого исходного кода действительно приятно.
Это хорошо для небольших проектов. Я не думаю, что это работает для больших проектов. Системы сборки существуют по причине.
Плохо
Итак, вышесказанное рисует очень красивую картину Го. Жаль … потому что так много, очень, очень, очень плохо в языке.
Вещи изменчивы
Нет реальной возможности сделать вещи неизменными, а наличие неизменяемых / постоянных ссылок является краеугольным камнем написания многопоточного кода.
Недостаточно выражений
if/else
является оператором, а не выражением. Это приводит к дрянному коду:
1
2
3
4
5
6
7
|
val s string if condition { s = "some value" } else { s = "some other value" } |
Там даже нет арендного оператора. Итак, у нас есть 6 строк кода для:
1
|
val s = if (condition) "some value" else "some other value" |
Глупый синтаксис
В Go очень много глупых синтаксических операций. Например, для циклического перебора коллекции требуется range
(это ключевое слово, функция, операция, что такое range
?):
1
2
3
|
for v := range data { ... } |
Я имею в виду, что даже Java имеет for (v in data) {...}
. Итак, у Го есть этот range
, который ощущается как болт.
Еще одно замечание — как Go работает с тестированием типов:
1
2
3
4
5
6
|
val x int switch v := thing.(type) { case string: x = len(v) case int : x = v } |
В приведенном выше примере v
магически разыгрывается в зависимости от его типа. Сравните это со Scala:
1
2
3
4
|
val x = thing match { case v: String => v.length() case v: Int => v } |
В Go много глупых синтаксических хаков. Каждый имеет смысл в изоляции, но как коллекция, они просто боль.
Не убежден … как насчет:
1
2
|
x := "thing" val x2 = "thing" // same thing... different syntax |
Слишком много мнений
Иди очень, очень, очень самоуверенный. Он не скомпилирует код, если есть неиспользуемая переменная, неиспользуемый импорт и множество других предполагаемых грехов.
Да, я понимаю … если вы собираете для производства, да, блин на то, что будет предупреждениями. Но если я закомментирую блок кода, пока я нахожусь в цикле разработки, часто я получаю ошибки компиляции … тогда мне придется комментировать больше кода, чтобы компиляция работала. Это отстой. Он прерывает циклы быстрой компиляции и попытки и не может использовать REPL . Итак, разработка Go примерно на 30% медленнее, чем нужно.
Обработка ошибок в стиле 1970-х годов
В Go нет исключений. Только panic
которая изящно останавливает процесс.
Все, что может потерпеть неудачу, возвращает кортеж из 2 элементов … возвращаемое значение и ошибку:
1
|
info, err := openAFile( "/filename" ) |
Как и любой программист на C в мире, который игнорировал ошибки в 1980-х годах, он предлагает людям:
1
|
info, _ := openAFile( "/filename" ) |
Потому что, да, я вернусь к этому позже.
Я понимаю, что наличие семантики обработки исключений в замыканиях, работа с исключениями, которые раскручивают стек из подпрограммы Go, и все другие подобные вещи нетривиальны, чтобы получить право. Но что еще хуже, так это то, что вы можете полностью понизить Иди наказан полностью.
Итак, у нас есть другой язык программирования, который поощряет разработчиков не обрабатывать исключительные ситуации. Вздох.
Или, другими словами, если бы дизайнеры Go провели некоторое время с Erlang, они могли бы добавить к каналам простую иерархию супервизора, поэтому, когда канал умирает, есть код, который имеет дело.
Некоторые дженерики, но слишком мало
Go поддерживает некоторые ограниченные формы обобщений для внутренних карт, массивов, каналов и срезов . Ура!
Но дженерики имеют ужасный синтаксис:
1
|
myMap := map[string] interface {}{ "foo" : 33 , "bar" : "baz" , "dog" : true } |
Да … второй общий тип находится вне квадратных скобок. О да, это ужасно ужасно.
Ох … есть ли «множественные возвращаемые значения» , то есть универсальный тип продукта … но вы не можете создать его, вы не можете отправить его на канал, вы можете только вернуть один, а возвращенный тип продукта должен быть распакован с множественное назначение.
Кроме того, вы не можете указать универсальные шаблоны … и это приводит к большому количеству копирования / вставки кода. Как в дни С
Нет сборов операций
Это 2015. У Java и JavaScript есть map
и filter
по коллекциям. Иди не Это глупо и неправильно на его лице.
Как неправильно? Ну, настолько безумно глупо, что я понятия не имею, о чем думали дизайнеры Go.
Разве они не потратили, вы знаете, 10 минут на ЛЮБОЙ ДРУГОЙ ЯЗЫК ? map
и filter
— это ТОЛЬКО ЧТО ВЫ ДЕЛАЕТЕ с коллекциями.
Верхний регистр против нижнего регистра
Если вы даете функции имя в нижнем регистре, функция является чем-то приватным (может быть, это локальный файл, может быть, это пакет… не совсем уверен). То же самое для поля в struct
.
Верхний регистр является публичным.
Да … это хороший маркер …
Но многие из встроенных функций (например, len(...)
) строчные. Таким образом, встроенный в Go материал строчный, но общедоступный, но для всех остальных — верхний регистр для совместного использования.
Отсутствие последовательности вызывает разочарование.
Итак, Го слаб
Мой общий вывод от Go — слабое решение. Он делает несколько вещей очень хорошо. Он имеет массу синтаксических и дизайнерских проблем. Это очень прискорбно, потому что у команды Го был реальный шанс сделать что-то хорошо … а они этого не сделали.
Ссылка: | Мои мысли о движении от нашего партнера JCG Дэвида Поллака в блоге DPP в блоге. |