Попробовал немного рифмовать в названии. Не принимайте всерьез слово «за».

Для разработчика, привыкшего к ключевому слову class, Go или Golang (как его часто называют) — это что-то вроде отключения. Объектов нет, но struct. Нет наследования, есть композиция. Иерархии исключений нет, но error. Есть pointer или их отсутствие. Параллелизм не одобряется (что!). В этой статье я намерен обсудить некоторые ловушки, с которыми сталкиваются опытные разработчики, пытающиеся изучить Go и стать продуктивнее.

Кто переместил мои объекты

Я часто задавался вопросом, почему создатели Go отказались от объектов и отдали предпочтение struct. Можно подумать, что в промежуточном байтовом коде нет Объектов, тогда зачем они в самом коде. Посмотрите на класс Animal, который имеет два поля и два метода.

В машинном коде он транслируется в разные части памяти. Излишне говорить, что память команд повторно используется в разных экземплярах class Animal.

Итак, как мы видим, поля в классе транслируются в память, а методы attached в поля выполняют какое-то действие. Все методы получают указатель this, который может манипулировать данными. Почти все языки объектно-ориентированного программирования переписывают методы, чтобы включить указатель this. Это объектно-ориентированное программирование с высоты птичьего полета.

Теперь вы можете понять, почему struct имеет большой смысл. Вы определяете поля в struct, а затем применяете к ним методы attach с помощью receiver. Вы могли заметить, что в Go указатель this заменяется явно присоединенным receiver — тем, который входит в (a Animal).

Написать вместо наследования

Одним из основных преимуществ ООП было наследование, несмотря на его недостатки. Основным аргументом было повторное использование кода. Допустим, у нас есть новый класс Lion, который добавляет дополнительное поле home. Но мне нужны другие методы в Animal. Естественно, вы extend переопределите методы, которые, по вашему мнению, могут не относиться к базовому классу.

Теперь, если цель состоит в том, чтобы просто получить методы суперкласса, почему бы просто не использовать повторно функции, определенные как есть. Это именно тот способ, которым Go делает это. Переписывание на Go

Составив Animal в строке 3, вы бесплатно получите все его методы и члены. Это очень странная нотация, но она делает именно то, что нам нужно. Также инициализация структуры немного более странная (сначала). Но потом, если вы думаете, что это compose, тогда все начинает обретать смысл.

Исключительно??

У меня проблема с тем, как java обрабатывает Exception . На первый взгляд выглядит безобидно. Нам дана иерархия исключений, где мы можем создавать всевозможные исключения и бросать их в наш код. Все идет нормально. Но что, если мы воспользуемся библиотекой. Они решили пошалить со своими исключениями, и внезапно мы, как потребители, вынуждены обрабатывать все эти исключения, создавая бесконечные catch. Код, подобный приведенному ниже, не редкость в кодовой базе Java.

Конечно, есть много синтаксического сахара и всемирно известных @SneakyThrows для облегчения проблемы, но проблемы не должно было быть в первую очередь. Моя главная проблема с обработкой некоторого случайного исключения из другой библиотеки заключается в том, что оно нарушает abstraction , одно из обещаний ООП. Упс!!

Введите error . Go очень подробно описывает обработку ошибок. В Go идиоматично обрабатывать ошибки тут и там. Не оставляйте нисходящий поток для обработки ваших ошибок. Следовательно, обработка ошибок, как показано ниже, является нормой в Go. Негласное соглашение состоит в том, чтобы последний возвращаемый параметр в func был error, если он его выдает.

указатели

Нравится вам это или нет, в Java есть указатели, но тонкие. В Go есть возможность явных указателей, если это необходимо. Обычно, когда вы передаете структуры в Go, они копируются, как primitive в Java. Это означает, что объекты копируются в стек. Полученная программа, вероятно, работает быстрее, поскольку циклы процессора быстрее, но доступ к памяти - нет.
В Java все объекты создаются в куче или в памяти, это означает, что мы передаем ссылку (указатель, если хотите) на объект, что дает возможность вызываемому объекту изменять объект. В Go вам придется дать эту возможность, объявив об обходе указателя. Вам не нужно передавать указатель, если вам не нужно изменить рассматриваемый объект.

Это приводит к шаблону наличия pointer receiver в некоторых случаях, когда вы действительно хотите изменить объект.

параллелизм

Я люблю параллелизм и использую его как инструмент, чтобы сделать мои программы более эффективными (по крайней мере, на мой взгляд, реальность другая). Дело в том, что параллелизм очень сложно сделать правильно, и часто, когда что-то идет не так, это происходит в продакшене! В Go есть все возможности параллелизма, которые есть в Java, за исключением шумихи. Но снова использование не одобряется. Вместо этого Go предлагает использовать channel . По сути, это примитив в Go, где вы можете писать и читать.

Рассмотрим эту старую добрую программу производитель-потребитель. Производитель(и) производит, а некоторые потребители потребляют. Между ними обычно находится LinkedBlockingQueue, который обрабатывает буфер элементов, произведенных для потребления. В Go это канал с типом chan. Программа ниже показывает несколько вещей, а именно. использование канала для буферизации входящих и исходящих данных, шаблон канала done и подпрограммы Go, которые эквивалентны Thread(почти), вызываемому с go doSome()

Управление пакетами

Если вы не хотите постоянно собирать каждый бит кода до уровня byte, вам нужно будет использовать библиотеку — желательно с открытым исходным кодом — для выполнения этой работы. В большинство современных языков программирования встроено хорошее управление пакетами. Голанг не исключение. Go использует немного другой подход, когда дело доходит до управления пакетами.

Для библиотек нет repository. В Java у нас есть репозиторий maven. На узле есть репозиторий npm. Go автоматически индексирует библиотеки, загруженные в системы контроля версий, такие как github, и делает их доступными в https://pkg.go.dev/. Он делает некоторую оптимизацию для пометки версии и, следовательно, поддерживает копию, но pkg.go.dev следует рассматривать как документацию, а не репозиторий. Я должен предупредить вас, что все управление модулями в Go очень самоуверенно.

Заключение

У Go есть свои сильные и слабые стороны. Я не думаю, что существует какой-то один язык программирования, отвечающий всем требованиям, всегда есть подвох. Если в этой статье вы задались вопросом, использовать ли Go в своем следующем проекте, то вы можете быть разочарованы. Я уверен, что вы знаете свой проект и можете принять взвешенное решение.

Для меня простота Go — самый интересный элемент. Исходя из фона Java, я привык к бесконечному количеству библиотек и их аннотаций повсюду только для простой сериализации. Все это часто упрощается в Go, который предоставляет мощные абстракции для разработки современного кода с гораздо меньшим объемом памяти, не отказываясь от производительности.