Что я узнал нового, изучая Go
Всем привет! Совсем недавно я кодил на Голанге и вот теперь решил поделиться с вами некоторыми наблюдениями.
Мощь стандартной библиотеки
Я обнаружил, что все, что я могу захотеть сделать, можно реализовать, и причем довольно хорошо, используя стандартную библиотеку. Она конечно не идеальная, но я не нашел ничего такого, чтобы я не мог сделать при помощи нее. Нужно вызвать API? Просто импортируйте net/http. Хотите конвертировать что-то в JSON? Просто импортируйте encoding/JSON. Стандартная библиотека Go удовлетворяет всем вашим основным потребностям по части функциональности, включая: ввод-вывод, работу с файловой системой, шифрование и т. д. До сих пор единственной вещью, которую я бы хотел изменить в библиотеке, был стандартный регистратор. Для этого я заменил его на zap logger.
Управление зависимостями в Go можно бы сделать и лучше
До сих пор я использовал модули go исключительно как фичу в Go 1.11, который зарелизился в августе 2018 года. Это позволяет каждому проекту жить в отдельном каталоге в любом месте файловой системы и иметь version controlled зависимости. Насколько я понял, это первый официальный способ получения конкретных зависимостей проекта. К моему большому сожалению, я обнаружил, что некоторые вещи с использованием модулей Go пока просто не работают. Например, я не смог использовать Revel, работу с которым планировал изучить и описать в моей серии постов о фреймворке. Go нужно немного больше времени, чтобы все стандартизировать и получить все библиотеки на борту, чем таким менеджерам пакетов, как npm и composer.
Go универсален
Особенно хочу рассказать о трех фичах в go, которые предоставляют разработчику большую гибкость: методы для любого типа данных, множественные возвращаемые значения для функций и интерфейсы.
Методы использующие любые типы данных
Магическим образом Go реализует такую схему, что у любого типа данных могут быть методы. К примеру, допустим, я хочу взять int и удвоить его.
type Doubler intfunc (d *Doubler) Double() { (*d) = (*d)*2 }func main() { var num Doubler num = 3 num.Double() fmt.Println(num) //prints 6! }
Это очень удобно, но, не злоупотребляйте таким использованием. Довольно очевидно, что эта реализация привносит немного спаггети кода.
Несколько возвращаемых значений
Как вы поняли, функции go могут возвращать несколько значений любого типа данных. Это дает намного большую свободу, которую мы не имеем в других языках и обычно вынужденны искать обходные пути . К примеру, хотим мы сравнить двух людей и проверить, одинаковы ли они:
type Person struct { Name string Age int } //isSamePerson takes two Person structs and returns whether they are equal //It also returns a list of differences func isSamePerson(firstPerson Person, secondPerson Person) (bool, []string) { differences := []string{} isSame := true if firstPerson.Name!= secondPerson.Name{ differences = append(differences, "Names do not match") isSame = false } if firstPerson.Age != secondPerson.Age { differences = append(differences, "Ages do not match") isSame = false } return isSame, differences }
Вы можете увидеть здесь функцию, которая проверяет, являются ли два человека одинаковыми, и мы можем получить логическое значение, которое нам нужно, и к тому же проследить за отличиями между людьми.
Интерфейсы
Интерфейсы в Go работают совсем не так, как в других языках. Интерфейсы представляются в роли контракта между двумя частями вашего кода, который ответственен за определение поведения функций. В большинстве объектно-ориентированных языков интерфейс - это явное объявление класса, указывающее, что он должен иметь указанные функции с определенными требованиями в интерфейсе. Go использует другой подход к интерфейсам, он определяет их неявно. Любой тип данных, который имеет методы, соответствующие сигнатуре интерфейса, является приемлемым для использования. На мой взгляд, это решение имеет имеет как плюсы, так и минусы. В сочетании со способностью Голанга иметь методы для любого типа данных, это обеспечивает очень гибкое использование. Это означает, что любой тип данных может удовлетворить интерфейс, если методы совпадают. Кроме того, тип данных может потенциально удовлетворить несколько интерфейсов без конфликта. Но, я так же обнаружил, что при программировании на Go сложнее убедиться, что вы реализуете интерфейс. Во многом это связано с неявной природой интерфейсов Go. Время для примера!
type Doubleable interface { Double() } type DoubleInt int func (d *DoubleInt) Double() { (*d) = (*d) * 2 } type DoublePeople struct { NumPeople int } func (d *DoublePeople ) Double() { d.NumPeople *= 2 } func main() { var numInt DoubleInt = 1 people:= DoublePeople{NumPeople: 4} doDouble(&numInt) doDouble(&people) fmt.Println(numInt)//prints 2 fmt.Println(people.NumPeople)//prints 8 } //doDouble takes a doubler and doubles it func doDouble(doubler Doubleable) { doubler.Double() }
И тип int, и тип struct могут быть удвоены и оба могут быть переданы в функцию doDouble, поскольку они оба неявно удовлетворяют интерфейсу Doubleable.
Прокаченный набор инструментов в Go
В отличие от других языков, с которыми я работал, Go имеет несколько хороших встроенных инструментов. Модульное тестирование, бенчмаркинг и профилирование включены в стандартный набор утилит и не требуют дополнительной установки. Кроме того, отладка также работает даже при дефолтном запуске. Это означает, что начать писать код go довольно просто, по крайней мере, при использовании модулей go. Go vet может проверить ваш код на наличие общих проблем и отформатировать кода в стандарте Go. В целом по сравнению с PHP и JS, нужно установить гораздо меньше вещей, чтобы начать писать и тестировать код. Это не означает, что все инструменты идеально подходят для всех, например, вы можете захотеть расширить пакет тестирования с помощью библиотеки утверждений или BDD фреймворка. Regardless Go предоставляет вам инструменты, необходимые для написания хорошего, хорошо протестированного кода.
Go - отличный язык, и, для меня, он до сих пор считается довольно простым языком. Здесь очень мало синтаксиса и достаточно небольшое количество концепций, которые нужно знать, чтобы эффективно использовать весь потенциал языка.
Перевод статьи Some Observations While Learning Golang