Golang, похоже, становится довольно популярным в качестве языка программирования для некоторых интересных новых технологий, таких как Docker , Kubernetes и OpenShift . К счастью, все они тоже с открытым исходным кодом, что означает, что мы все можем внести свой вклад в эти сообщества и принять участие. Очевидным преимуществом open source, которое оказывается чрезвычайно ценным и полезным во многих обстоятельствах, является очевидное: открытый исходный код . Я не могу сказать вам, как часто мне приходилось прыгать в источник проекта, независимо от языка программирования, используемого для его реализации, чтобы по-настоящему понять, что он делает, или даже что более важно: почему он не делает что-то, что, по словам доктора, должно (или когда нет документов). Код читается гораздо чаще, чем написано, поэтому он помогает понять, как его читать.
В свое время я выучил немало языков программирования (C, C ++, C #, Java, Python, Scala, Groovy, Assembly, JavaScript и т. Д.), И теперь это Go. Я потратил несколько недель, чтобы научиться читать Golang и читать исходные файлы из кодовых баз Kubernetes, Fabric8 и OpenShift Origin, чтобы понять их немного глубже, и я думаю, что это будет полезно для разработчиков, знакомых с другим языком программирования. быстро сопоставить некоторые концепции, скажем, с Java, с Голангом с простой целью преодоления страха вступления, чтобы помочь этим сообществам или, более эгоистично, прочитать и понять, как некоторые из новых технологий написаны на Голанге. на самом деле работает.
Вот несколько ключевых моментов, которые поначалу выделялись для меня. Не стесняйтесь, чтобы Tweet (@christianposta) меня другие, которые вы чувствуете, могут быть добавлены здесь, или оставить комментарий. Эта статья определенно не предназначена для введения в Go и не является полным Java-> Go-отображением. Цель этой статьи — быстро помочь разработчикам Java понять несколько распространенных идиом Go, с точки зрения того, как это соотносится с Java.
Структура проекта
Похоже, что общепринятым соглашением для проектов Golang является размещение всех двоичных исходных файлов cli или файлов в «основном» пакете в папке cmd
которая находится в корне дерева исходного кода. Пакеты, которые реализуют множество функциональных возможностей и представляют собой упорядоченные наборы типов, констант, переменных и функций, обычно можно найти в папке pkg
в корне исходного каталога.
пакеты
Golang организует свой код в пакеты, аналогично Java. Вы объявляете, в каком пакете находится исходный файл (и все его константы, типы, функции и т. Д.), Вводя package <package_name>
в верхней части исходного файла; однако, в отличие от Java, вы не указываете полный путь (местоположение каталога), только имя. Пример:
1
|
package api |
Поэтому, если у вас есть пакет «api / endpoints», у вас будет такая структура каталогов в файловой системе (например, ./pkg/api/endpoints), но пакет endpoints
будет объявлен в исходных файлах в каталоге endpoints
, но они будут выглядеть так:
1
|
package endpoints |
Импорт пакетов
Мы можем импортировать пакеты, как в Java, с помощью следующего:
1
2
3
4
5
6
7
|
import ( stderrs "errors" "time" "golang.org/x/net/context" "k8s.io/kubernetes/pkg/auth/user" ) |
Мы можем использовать пакеты в исходном коде, основываясь на последнем имени пакета в пути пакета. Например, в приведенном выше примере мы импортируем k8s.io/kubernetes/pkg/auth/user
и из кода мы можем ссылаться на элементы внутри этого пакета с помощью user.Foo()
. Если мы хотим переименовать пакет в нашем исходном файле, чтобы он не конфликтовал с другими именами, мы можем сделать то, что сделали выше:
1
2
3
|
import ( stderrs "errors" ) |
И обратитесь к пакету errors
в нашем исходном коде как stderrs.Foo()
Основной пакет
main
пакет — это то, где Голанг ищет точку входа в приложение. main
пакет должен иметь функцию main()
которая не принимает аргументов и не возвращает значений:
1
|
func main() { … } |
Как уже упоминалось, этот пакет обычно находится в папке cmd
в корневом каталоге.
Область / видимость типов, констант, функций
В golang, чтобы обеспечить область видимости для структуры / типа / функции / переменной, которая должна быть представлена вне пакета, первый символ в символе имеет значение. Например, в пакете foo
, если у вас есть функция с именем func Bar()
, то, поскольку «Bar» имеет первую букву в верхнем регистре, она будет использоваться вне пакета. Если вы импортируете пакет foo
, вы сможете получить доступ к foo.Bar()
. Если бы «бар» был в нижнем регистре, он был бы скрыт — то есть регистр первой буквы определяет видимость
Методы могут возвращать несколько значений
Функция или метод в golang (есть различие) может возвращать «кортеж» или возвращение нескольких значений. Например, вызов функции, которая возвращает несколько значений, выглядит следующим образом:
1
|
internalCtx, ok := foo.bar(context.Context) |
Классы, структуры, методы
В Java у нас есть классы, но в Go у нас есть структуры. Структуры могут иметь методы, поэтому они как классы.
Например:
1
2
3
4
|
type Rectangle struct { width int height int } |
Это структура данных с именем «Прямоугольник», которая имеет два поля: width
и height
. Мы можем создать новый Rectangle
так:
1
|
r := new (Rectangle) |
и мы можем ссылаться на его поля, как это:
1
2
|
r.width = 10 r.height = 5 |
Мы можем написать методы на Struct, который работает с полями структуры, например так:
1
2
3
|
func (r *Rectangle) area() int { return r.width * r.height } |
Поэтому, если вы видите такие идиомы в коде golang, подумайте «классы Java»
Тип наследования
Golang целенаправленно не имеет типа «extends», как в Java. Наследование осуществляется с помощью композиции (вроде как мы должны делать это в Java как «лучшую практику» в любом случае :)). Однако, это действительно похоже на ключевое слово «extends» в Java с точки зрения его видимости для программиста. Например:
1
2
3
4
5
|
type Rectangle struct { Shape width int height int } |
В этом примере Rectangle имеет анонимное поле типа Shape
. Все поля и методы Shape
будут видны на объектах Rectangle
.
Однако следует отметить, что, поскольку Shape
Rectangle
«is-a» не похожа на Java, где мы можем передать Rectangle
функции, которая принимает Rectangle
в качестве параметра. Это потерпит неудачу в Go. Чтобы получить этот тип «типового» полиморфизма, вы должны использовать интерфейсы Go (следующий раздел)
Полиморфизм, интерфейсы и типирование утки
В Java у нас есть определенные типы интерфейсов, которые определяют поведение на основе методов, которые должны быть реализованы классами, которые претендуют на этот тип. В Go у нас действительно есть интерфейсы, которые делают то же самое, но классы на самом деле не объявляют, что собираются реализовать их специально: они просто реализуют методы, а затем они соответствуют этому интерфейсу.
Например, этот интерфейс объявляет тип Shape с методом Print ():
1
2
3
|
type Shape interface { Print() } |
Однако, когда мы создаем наши Structs, нам вообще не нужно объявлять это с помощью «реализаций», как мы делаем в Java: мы просто реализуем методы, и они могут передаваться функциям и обрабатываться как этот тип:
1
2
3
4
5
6
7
8
|
type Rectangle struct { width int height int } func (r *Rectangle) Print() { fmt.println( "Rectangle!" ); } |
В этом случае объект Rectangle может быть передан функциям, которые ожидают тип Shape
поскольку он реализует все методы для этого типа.
Для петель
Пример цикла for с go:
1
2
3
|
for i := 1 ; i <= 10 ; i++ { fmt.Println(i) } |
Однако при итерации массива (или чего-то, что выглядит как массив, например, строка, карта, срез и т. Д.), Вы можете использовать оператор диапазона следующим образом (предположим, что foo
— это список):
1
2
3
|
for v := range foo { fmt.println( "value=" +v); } |
Если вам нужно знать индекс списка во время его итерации, он выглядит следующим образом:
1
2
3
|
for i, v := range foo { fmt.println( "index " + i + "has value=" +v); } |
Пока петли
В Go нет циклов while, do-while, foreach и т. Д. Вы просто снова используете цикл for следующим образом:
1
2
3
4
5
|
sum := 1 for sum < 1000 { sum += sum } fmt.Println(sum) |
Или можете сделать бесконечный цикл while:
1
2
3
|
for { something... } |
Указатели и ссылки
Голанг явно использует указатели и ссылки, тогда как Java в основном это скрывает. Например, в Java мы могли бы сделать
Shape shape = new Shape()
и затем shape.foo()
но в Go мы должны напрямую позаботиться об указателях:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
type Rectangle struct { width int height int } func updateRectangle(r *Rectangle){ r.width = 5 ; r.height = 10 ; } func main() { r := Rectangle{ 20 , 30 } updateRectangle(&r) } |
Когда основная функция заканчивается, прямоугольник r
будет иметь значения width = 5 и height = 10, как и следовало ожидать. Обратите внимание, мы должны сделать явные ссылки на указатели.
Вывоз мусора
Голанг — это язык для сбора мусора; нет необходимости явно освобождать память самостоятельно (я знаю, что вы думали, когда видели раздел указателей и ссылок выше :)).
Если вы являетесь Java-разработчиком и хотели бы добавить больше к этому, пожалуйста, дайте мне знать (@christianposta)! Или, если вы являетесь разработчиком, и я что-то здесь неверно прошу, поправьте меня! Надеюсь, что это полезно …
Ссылка: | Quick Go-lang для разработчиков Java от нашего партнера JCG Кристиана Поста в блоге |