Статьи

Мои мысли на ходу

Мех

Я работал над проектом, который должен запускаться как небольшой код. Я занимаюсь Си с 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 в блоге.