Содержание

Структуры и интерфейсы — Введение в программирование на Go

Несмотря на то, что вполне можно писать программы на Go используя только встроенные типы, в какой-то момент это станет очень утомительным занятием. Вот пример — программа, которая взаимодействует с фигурами:

package main
import ("fmt"; "math")
func distance(x1, y1, x2, y2 float64) float64 {
    a := x2 - x1
    b := y2 - y1
    return math.Sqrt(a*a + b*b)
}
func rectangleArea(x1, y1, x2, y2 float64) float64 {
    l := distance(x1, y1, x1, y2)
    w := distance(x1, y1, x2, y1)
    return l * w
}
func circleArea(x, y, r float64) float64 {
    return math.Pi * r*r
}
func main() {
    var rx1, ry1 float64 = 0, 0
    var rx2, ry2 float64 = 10, 10
    var cx, cy, cr float64 = 0, 0, 5
    fmt.Println(rectangleArea(rx1, ry1, rx2, ry2))
    fmt.Println(circleArea(cx, cy, cr))
}

Отслеживание всех переменных мешает нам понять, что делает программа, и наверняка приведет к ошибкам.

Структуры

С помощью структур эту программу можно сделать гораздо лучше.

Структура — это тип, содержащий именованные поля. Например, мы можем представить круг таким образом:

type Circle struct {
    x float64
    y float64
    r float64
}

Ключевое слово type вводит новый тип. За ним следует имя нового типа (Circle) и ключевое слово struct, которое говорит, что мы определяем структуру и список полей внутри фигурных скобок. Каждое поле имеет имя и тип. Как и с функциями, мы можем объединять поля одного типа:

type Circle struct {
    x, y, r float64
}

Инициализация

Мы можем создать экземпляр нового типа Circle несколькими способами:

var c Circle

Подобно другим типами данных, будет создана локальная переменная типа Circle, чьи поля по умолчанию будут равны нулю (0 для int, 0.0 для float, "" для string, nil для указателей, …). Также, для создания экземпляра можно использовать функцию new.

c := new(Circle)

Это выделит память для всех полей, присвоит каждому из них нулевое значение и вернет указатель (*Circle). Часто, при создании структуры мы хотим присвоить полям структуры какие-нибудь значения. Существует два способа сделать это. Первый способ:

c := Circle{x: 0, y: 0, r: 5}

Второй способ — мы можем опустить имена полей, если мы знаем порядок в котором они определены:

c := Circle{0, 0, 5}

Поля

Получить доступ к полям можно с помощью оператора . (точка):

fmt.Println(c.x, c.y, c.r)
c.x = 10
c.y = 5

Давайте изменим функцию circleArea так, чтобы она использовала структуру Circle:

func circleArea(c Circle) float64 {
    return math.Pi * c.r*c.r
}

В функции main у нас будет:

c := Circle{0, 0, 5}
fmt. Println(circleArea(c))

Очень важно помнить о том, что аргументы в Go всегда копируются. Если мы попытаемся изменить любое поле в функции circleArea, оригинальная переменная не изменится. Именно поэтому мы будем писать функции так:

func circleArea(c *Circle) float64 {
    return math.Pi * c.r*c.r
}

И изменим main:

c := Circle{0, 0, 5}
fmt.Println(circleArea(&c))

Методы

Несмотря на то, что программа стала лучше, мы все еще можем значительно её улучшить, используя метод — функцию особого типа:

func (c *Circle) area() float64 {
    return math.Pi * c.r*c.r
}

Между ключевым словом func и именем функции мы добавили «получателя». Получатель похож на параметр — у него есть имя и тип, но объявление функции таким способом позволяет нам вызывать функцию с помощью оператора .:

fmt.Println(c.area())

Это гораздо проще прочесть, нам не нужно использовать оператор & (Go автоматически предоставляет доступ к указателю на Circle для этого метода), и поскольку эта функция может быть использована только для Circle мы можем назвать её просто

area.

Давайте сделаем то же самое с прямоугольником:

type Rectangle struct {
    x1, y1, x2, y2 float64
}
func (r *Rectangle) area() float64 {
    l := distance(r.x1, r.y1, r.x1, r.y2)
    w := distance(r.x1, r.y1, r.x2, r.y1)
    return l * w
}

В main будет написано:

r := Rectangle{0, 0, 10, 10}
fmt.Println(r.area())

Встраиваемые типы

Обычно, поля структур представляют отношения принадлежности (включения). Например, у Circle (круга) есть radius (радиус). Предположим, у нас есть структура

Person (личность):

type Person struct {
    Name string
}
func (p *Person) Talk() {
    fmt.Println("Hi, my name is", p.Name)
}

И если мы хотим создать новую структуру Android, то можем сделать так:

type Android struct {
    Person Person
    Model string
}

Это будет работать, но мы можем захотеть создать другое отношение. Сейчас у андроида «есть» личность, можем ли мы описать отношение андроид «является» личностью? Go поддерживает подобные отношения с помощью встраиваемых типов, также называемых анонимными полями. Выглядят они так:

type Android struct {
    Person
    Model string
}

Мы использовали тип (Person) и не написали его имя. Объявленная таким способом структура доступна через имя типа:

a := new(Android)
a.Person.Talk()

Но мы также можем вызвать любой метод Person прямо из Android:

a := new(Android)
a.Talk()

Это отношение работает достаточно интуитивно: личности могут говорить, андроид это личность, значит андроид может говорить.

Интерфейсы

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

Пример интерфейса для фигуры (Shape):

type Shape interface {
    area() float64
}

Как и структуры, интерфейсы создаются с помощью ключевого слова type, за которым следует имя интерфейса и ключевое слово interface. Однако, вместо того, чтобы определять поля, мы определяем «множество методов». Множество методов — это список методов, которые будут использоваться для «реализации» интерфейса.

В нашем случае у Rectangle и Circle есть метод area, который возвращает float64, получается они оба реализуют интерфейс Shape. Само по себе это не очень полезно, но мы можем использовать интерфейсы как аргументы в функциях:

func totalArea(shapes ...Shape) float64 {
    var area float64
    for _, s := range shapes {
        area += s.area()
    }
    return area
}

Мы будем вызывать эту функцию так:

fmt.Println(totalArea(&c, &r))

Интерфейсы также могут быть использованы в качестве полей:

type MultiShape struct {
    shapes []Shape
}

Мы можем даже хранить в MultiShape данные Shape, определив в ней метод area:

func (m *MultiShape) area() float64 {
    var area float64
    for _, s := range m. shapes {
        area += s.area()
    }
    return area
}

Теперь MultiShape может содержать Circle, Rectangle и даже другие MultiShape.

Задачи

  • Какая разница между методом и функцией?

  • В каких случаях могут пригодиться встроенные (скрытые) поля?

  • Добавьте новый метод

    perimeter в интерфейс Shape, который будет вычислять периметр фигуры. Имплементируйте этот метод для Circle и Rectangle.

Язык Go для начинающих / Хабр

Цель этой статьи — рассказать о языке программирования Go (Golang) тем разработчикам, которые смотрят в сторону этого языка, но еще не решились взяться за его изучение. Рассказ будет вестись на примере реального приложения, которое представляет из себя RESTful API веб-сервис.

Передо мной стояла задача разработать бэкэнд к мобильному сервису. Суть сервиса довольно проста.

Мобильное приложение, которое показывает посты пользователей, находящихся рядом с текущим местоположением. На посты пользователи могут оставлять свои комментарии, которые тоже, в свою очередь, можно комментировать. Получается своеобразный гео-форум.

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

Основные преимущества языка Go:

  • Простой и понятный синтаксис. Это делает написание кода приятным занятием.
  • Статическая типизация. Позволяет избежать ошибок, допущенных по невнимательности, упрощает чтение и понимание кода, делает код однозначным.
  • Скорость и компиляция. Скорость у Go в десятки раз быстрее, чем у скриптовых языков, при меньшем потреблении памяти. При этом, компиляция практически мгновенна. Весь проект компилируется в один бинарный файл, без зависимостей. Как говорится, «просто добавь воды». И вам не надо заботиться о памяти, есть сборщик мусора.
  • Отход от ООП. В языке нет классов, но есть структуры данных с методами. Наследование заменяется механизмом встраивания. Существуют интерфейсы, которые не нужно явно имплементировать, а лишь достаточно реализовать методы интерфейса.
  • Параллелизм. Параллельные вычисления в языке делаются просто, изящно и без головной боли. Горутины (что-то типа потоков) легковесны, потребляют мало памяти.
  • Богатая стандартная библиотека. В языке есть все необходимое для веб-разработки и не только. Количество сторонних библиотек постоянно растет. Кроме того, есть возможность использовать библиотеки C и C++.
  • Возможность писать в функциональном стиле. В языке есть замыкания (closures) и анонимные функции. Функции являются объектами первого порядка, их можно передавать в качестве аргументов и использовать в качестве типов данных.
  • Авторитетные отцы-основатели и сильное комьюнити. Роб Пайк, Кен Томпсон, Роберт Гризмер стояли у истоков. Сейчас у языка более 300 контрибьюторов. Язык имеет сильное сообщество и постоянно развивается.
  • Open Source
  • Обаятельный талисман

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

Итак, вернемся к нашей задаче. Хоть язык и не накладывает ограничений на структуру проекта, данное приложение я решил организовать по модели MVC. Правда View реализовывается на стороне клиента. В моем случае это был AngularJS, в перспективе — нативное мобильное приложение. Здесь я расскажу лишь об API на стороне сервиса.

Структура проекта получилась следующая:

/project/
	/conf/
		errors.go
		settings.go
	/controllers/
		posts.go
		users.go
	/models/
		posts.go
		users.go
	/utils/
		helpers.go
	loctalk.go

Программа в Go разделяется на пакеты (package), что указывается в начале каждого файла. Имя пакета должно соответствовать директории в которой находятся файлы, входящие в пакет. Так же, должен быть главный пакет main с функцией main(). Он у меня находится в корневом файле приложения loctalk.go. Таким образом, у меня получилось 5 пакетов: conf, controllers, models, utils, main.
Буду приводить неполное содержание файлов, а только минимально необходимое для понимания.

Пакет conf содержит константы и настройки сайта.

package conf
import (
	"os"
)
const (
	SITE_NAME string = "LocTalk"
	DEFAULT_LIMIT  int = 10
	MAX_LIMIT      int = 1000
	MAX_POST_CHARS int = 1000
)
func init() {
	mode := os.Getenv("MARTINI_ENV")
	switch mode {
	case "production":
		SiteUrl = "http://loctalk.net"
		AbsolutePath = "/path/to/project/"
	default:
		SiteUrl = "http://127.0.0.1"
		AbsolutePath = "/path/to/project/"
	}
}

Думаю, комментировать тут нечего. Функция init() вызывается в каждом пакете до вызова main(). Их может быть несколько в разных файлах.

Пакет main.

package main
import (
	"github.com/go-martini/martini"
	"net/http"
	"loctalk/conf"
	"loctalk/controllers"
	"loctalk/models"
	"loctalk/utils"
)
func main() {
	m := martini. Classic()
	m.Use(func(w http.ResponseWriter) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
	})
	m.Map(new(utils.MarshUnmarsh))
	Auth := func(mu *utils.MarshUnmarsh, req *http.Request, rw http.ResponseWriter) {
		reqUserId := req.Header.Get("X-Auth-User")
		reqToken := req.Header.Get("X-Auth-Token")
		if !models.CheckToken(reqUserId, reqToken) {
			rw.WriteHeader(http.StatusUnauthorized)
			rw.Write(mu.Marshal(conf.ErrUserAccessDenied))
		}
	}
	// ROUTES
	m.Get("/", controllers.Home)
	// users
	m.Get("/api/v1/users", controllers.GetUsers)
	m.Get("/api/v1/users/:id", controllers.GetUserById)
	m.Post("/api/v1/users", controllers.CreateUser)
	// …
	// posts
	m.Get("/api/v1/posts", controllers.GetRootPosts)
	m.Get("/api/v1/posts/:id", controllers.GetPostById)
	m.Post("/api/v1/posts", Auth, controllers.CreatePost)
	// ...
	m.Run()
}

В самом верху определяется имя пакета. Далее идет список импортируемых пакетов. Мы будем использовать пакет Martini. Он добавляет легкую прослойку для быстрого и удобного создания веб-приложений. Обратите внимание как импортируется этот пакет. Нужно указать путь к репозиторию откуда он был взят. А чтобы его получить, достаточно в консоли набрать команду go get github.com/go-martini/martini

Далее мы создаем экземпляр Martini, настраиваем и запускаем его. Обратите внимание на знак « := ». Это сокращенный синтаксис, он означает: создать переменную соответствующего типа и инициализировать ее. Например, написав a := «hello», мы создадим переменную a типа string и присвоим ей строку «hello».

Переменная m в нашем случае имеет тип *ClassicMartini, именно это возвращает martini.Classic(). * означает указатель, т. е. передается не само значение, а лишь указатель на него. В метод m.Use() мы передаем функцию-обработчик. Этот Middleware позволяет Martini делать определенные действия над каждым запросом. В данном случае, мы определяем Content-Type для каждого запроса. Метод m.Map() же позволяет привязать нашу структуру и использовать ее затем в контроллерах при необходимости (механизм dependency injection). В данном случае, я создал обертку для кодирования структуры данных в формат json.

Тут же мы создаем внутреннюю функцию Auth, которая проверяет авторизацию пользователя. Ее можно вставить в наши роуты и она будет вызываться до вызова контроллера. Эти вещи возможны благодаря Martini. С использованием стандартной библиотеки код получился бы немного другой.

Взглянем на файл errors.go пакета conf.

package conf
import (
	"fmt"
	"net/http"
)
type ApiError struct {
	Code        int    `json:"errorCode"`
	HttpCode    int    `json:"-"`
	Message     string `json:"errorMsg"`
	Info        string `json:"errorInfo"`
}
func (e *ApiError) Error() string {
	return e.Message
}
func NewApiError(err error) *ApiError {
	return &ApiError{0, http.StatusInternalServerError, err.Error(), ""}
}
var ErrUserPassEmpty = &ApiError{110, http.StatusBadRequest, "Password is empty", ""}
var ErrUserNotFound = &ApiError{123, http.StatusNotFound, "User not found", ""}
var ErrUserIdEmpty = &ApiError{130, http. StatusBadRequest, "Empty User Id", ""}
var ErrUserIdWrong = &ApiError{131, http.StatusBadRequest, "Wrong User Id", ""}
// … и т. д. 

Язык поддерживает возврат нескольких значений. Вместо механизма try-catch, очень часто используется прием, когда вторым аргументом возвращается ошибка. И при ее наличии, она обрабатывается. Есть встроенный тип error, который представляет из себя интерфейс:

type error interface {
	Error() string
}

Таким образом, чтобы реализовать этот интерфейс, достаточно иметь метод Error() string. Я создал свой тип для ошибок ApiError, который более специфичен для моих задач, однако совместим со встроенным типом error.

Обратите внимание на — type ApiError struct. Это определение структуры, модели данных, которую вы будете использовать постоянно в своей работе. Она состоит из полей определенных типов (надеюсь, вы успели заметить, что тип данных пишется после имени переменной). Кстати, полями могут быть другие структуры, наследуя все методы и поля. В одинарных кавычках « указаны теги. Их указывать не обязательно. В данном случае они используются пакетом encoding/json для указания имени в выводе json (знак минус «-» вообще исключает поле из вывода).

Обратите внимание, что поля структуры написаны с заглавной буквы. Это означает, что они имеют область видимости за пределами пакета. Если написать их с прописной буквы, они экспортироваться не будут, а будут доступны только в пределах пакета. Это же относится и к функциям и методам. Вот такой простой механизм инкапсуляции.

Двигаемся дальше. Определение func (e *ApiError) Error() string означает ни что иное, как метод данной структуры. Переменная e — это указатель на структуру, своего рода self/this. Соответственно вызвав метод .Error() на структуре, мы получим ее поле Message.

Далее мы определяем предустановленные ошибки и заполняем их поля. Поля вида http.StatusBadRequest — это значения типа int в пакете http для стандартных кодов ответа, своего рода алиасы. Мы используем сокращенный синтаксис объявления структуры &ApiError{} с инициализацией. По другому можно было бы написать так:

MyError := new(ApiError)
MyError.Code = 110
// …

Символ & означает получить указатель на данную структуру. Оператор new() так же возвращает указатель, а не значение. По-началу возникает небольшая путаница с указателями, но, со временем, вы привыкните.

Перейдем к нашим моделям. Приведу урезанную версию модели постов:

package models
import (
	"labix.org/v2/mgo/bson"
	"loctalk/conf"
	"loctalk/utils"
	"time"
	"unicode/utf8"
	"log"
)
// GeoJSON format
type Geo struct {
	Type        string     `json:"-"`          
	Coordinates [2]float64 `json:"coordinates"`
}
type Post struct {
	Id         bson.ObjectId `json:"id" bson:"_id,omitempty"`
	UserId     bson.ObjectId `json:"userId"`
	UserName   string		 `json:"userName"`
	ThumbUrl   string		 `json:"thumbUrl"`
	ParentId   bson.ObjectId `json:"parentId,omitempty" bson:",omitempty"`
	Enabled    bool          `json:"-"`
	Body       string        `json:"body"`
	Geo        Geo           `json:"geo"`
	Date       time. Time     `json:"date" bson:",omitempty"`
}
func NewPost() *Post {
	return new(Post)
}
func (p *Post) LoadById(id string) *conf.ApiError {
	if !bson.IsObjectIdHex(id) {
		return conf.ErrPostIdWrong
	}
	session := utils.NewDbSession()
	defer session.Close()
	c := session.Col("posts")
	err := c.Find(bson.M{"_id": bson.ObjectIdHex(id), "enabled": true}).One(p)
	if p.Id == "" {
		return conf.ErrPostNotFound
	}
	if err != nil {
		return conf.NewApiError(err)
	}
	return nil
}
func (p *Post) Create() (id string, err *conf.ApiError) {
    // validation
    switch {
    case p.UserId == "":
        err = conf.ErrUserIdEmpty
    case p.Body == "":
        err = conf.ErrPostBodyEmpty
    case utf8.RuneCountInString(p.Body) > conf.MAX_POST_CHARS:
        err = conf.ErrPostMaxSize
    case p.Geo.Coordinates[0] == 0.0 || p.Geo.Coordinates[1] == 0.0:
        err = conf.ErrPostLocationEmpty
    }
    if err != nil {
        return
    }
    p.Id = bson.NewObjectId()
    p.Geo.Type = "Point"
    p.Enabled = true
    p. Date = time.Now()
    session := utils.NewDbSession()
    defer session.Close()
    c := session.Col("posts")
    errDb := c.Insert(p)
    if errDb != nil {
        return "", conf.NewApiError(errDb)
    }
    return p.Id.Hex(), nil
}
func (p *Post) Update() *conf.ApiError {
	session := utils.NewDbSession()
	defer session.Close()
	c := session.Col("posts")
	err := c.UpdateId(p.Id, p)
	if err != nil {
		return conf.NewApiError(err)
	}
	return nil
}
func (p *Post) Disable() *conf.ApiError {
	session := utils.NewDbSession()
	defer session.Close()
	p.Enabled = false
	c := session.Col("posts")
	err := c.UpdateId(p.Id, p)
	if err != nil {
		return conf.NewApiError(err)
	}
	return nil
}
// … 

Здесь мы используем замечательный драйвер для MongoDb — mgo, чтобы сохранять данные. Для удобства, я создал небольшую обертку над api mgo — utils.NewDbSession. Логика работы с данными: сначала мы создаем объект во внутренней структуре языка, а затем, с помощью метода этой структуры, сохраняем его в базу данных.

Обратите внимание, что в этих методах мы везде используем наш тип ошибки conf.ApiError. Стандартные ошибки мы конвертируем в наши с помощью conf.NewApiError(err). Так же, важен оператор defer. Он исполняется в самом конце выполнения метода. В данном случае, закрывает соединение с БД.

Что ж, осталось взглянуть на контроллер, который обрабатывает запросы и выводит json в ответ.

package controllers
import (
	"encoding/json"
	"fmt"
	"github.com/go-martini/martini"
	"labix.org/v2/mgo/bson"
	"loctalk/conf"
	"loctalk/models"
	"loctalk/utils"
	"net/http"
)
func GetPostById(mu *utils.MarshUnmarsh, params martini.Params) (int, []byte) {
	id := params["id"]
	post := models.NewPost()
	err := post.LoadById(id)
	if err != nil {
		return err.HttpCode, mu.Marshal(err)
	}
	return http.StatusOK, mu.Marshal(post)
}
// ...

Здесь мы получаем из URL id запрашиваемого поста, создаем новый экземпляр нашей структуры и вызываем на ней метод LoadById(id) для загрузки данных из БД и заполнения данной структуры. Которую мы и выводим в HTTP ответ, предварительно преобразовав в json нашим методом mu.Marshal(post).

Обратите внимание на сигнатуру функции:

func GetPostById(mu *utils.MarshUnmarsh, params martini.Params) (int, []byte)

Входные параметры нам предоставляет Martini с помощью механизма внедрения зависимостей (dependency injection). И мы возвращаем два параметра (int, []byte) — число (статус ответа) и массив байт.

Итак, мы разобрали основные компоненты и подходы, используя которые, вы сможете сделать эффективный RESTful API интерфейс в короткие сроки. Надеюсь, статья была полезна и вдохновит некоторых из вас заняться изучением замечательного языка Go. Уверен, за ним будущее.

Для изучения могу порекомендовать хорошую книгу на русском «Программирование на языке Go» Марка Саммерфильда. И, конечно, больше практиковаться.

UPD: Tour Go на русском.

Где используется язык программирования Go?

Будущее за сложными проектами и корпорациями, способными собрать группы из сотен разработчиков. Это верно, но отрасли требуются простые и эффективные технологии, и такие языки программирования, которые в отличие от своих старших братьев позволяют создавать более гибкие проекты.

История создания

Днем рождения Go считается 21 сентября 2007 года, когда Роб Пайк, Роберт Гризмер и Кен Томпсон начали собирать материал для создания нового языка.

В январе 2008-го Кен начал работу над компилятором, а в мае того же года Ян Тейлор параллельно с коллегами стал разрабатывать интерфейс. В конце года к команде присоединился Расс Кокс, и совместными усилиями создателей проект был реализован.

10 ноября 2009 года Go стал доступен всем. Проект с открытым исходным кодом, логотипом которого стал суслик.

Кстати, правильное название языка – Go. Альтернативное название Golang появилось из-за сайта golang.org, потому что домен go.org оказался занят.

Существует версия, будто название Golang возникло из-за сочетания двух слов: Google Language. Однако официальные источники указывают, что именно Go – имя, а все остальные варианты – лишь удобные прозвища.

Новый язык программирования появился отчасти потому, что проекты в Google были очень сложными для существующих языков, медленными и негибкими. Создавая новый продукт постоянно приходилось выбирать между простотой, эффективностью и безопасностью.

Go – многопоточный компилируемый язык, основными преимуществами которого стали скорость, лаконичность и масштабируемость. К предкам Go относят семейство С с влиянием Pascal, Modula и Oberon.

К моменту создания Go самыми популярными языками были Java и C++, но программирование на них становилось все более сложным. Разработчики начали искать более гибкие варианты, такие, например, как Python.

Особенности GO

  • В этом языке отсутствует наследование – один из основных принципов объектно-ориентированного программирования. Это не означает, что в коде отсутствует иерархия. Она есть, но работает немного иначе, чем в более привычных нам вариантах. Новая модель ООП – без привычных объектов и классов, но в ней есть структуры данных с методами.
  • Использование сокращенного синтаксиса.
  • Параллелизм, позволяющий выполнять любую функцию одновременно с другими.

Достоинства:

  1. Простота. Упрощенный синтаксис позволяет уменьшить время на освоение языка и увеличить скорость разработки. Именно это делает Go подходящим для больших корпораций языком. Когда разработкой занимаются сотни программистов одновременно – это имеет значение.
  2. Быстрая компиляция.
  3. Хорошая версионность и бесплатные обновления.
  4. Большое количество библиотек. Многое можно реализовать через простую и понятную библиотеку Go, но также эффективно можно работать и с библиотеками на C.

Кстати, интересный момент с версионностью: каждый основной выпуск Go поддерживается до тех пор, пока не появится два новых основных выпуска.

Недостатки:

  1. Небольшое количество вакансий. Потребность даже в опытных в разработчиках на Go относительно невелика, а вариантов для джуниоров еще меньше.
  2. Принудительное форматирование. Это спорная особенность, которую не всегда можно считать недостатком: каждый следующий разработчик точно знает, чего ждать от кода предшественника.
  3. Упрощенный синтаксис иногда создает проблемы. Язык буквально навязывает его, не позволяя писать код по-своему. Если разработчику доступен только единственно верный вариант, сохранить уникальный стиль программирования у него не получится.

Почему стоит изучать Go?

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

Go используют такие компании, как IBM, Intel, Ozon, Avito и ВКонтакте. Есть достаточно большая вероятность, что и другие ИТ-гиганты будут постепенно переходить на него, поскольку в больших командах разработчиков этот выбор выглядит наиболее надежным.

За счет своей простоты, четкости и небольшого мануала, Go идеально подходит и для обучения новичков – его часто выбирают первым языком программирования.

***

Go – амбициозная попытка перенять лучшее у таких языков, как С++, Java и Pascal. Это очень простой язык, который можно освоить за короткое время, а значит и быстро вырастить своих специалистов внутри компании.

Конечно, это не последний эксперимент по созданию языка нового поколения: таких попыток было множество и наверняка будут еще. Нет гарантий, что именно Go станет максимально популярным в будущем, но совершенно точно, использованные при его создании принципы актуальны для любых новых языков. Будущее именно за ними, а это весомая причина изучить Go, согласитесь. А «Библиотека программиста» постарается вам в этом помочь. Удачи!

Документация

— Язык программирования Go

Язык программирования Go — это проект с открытым исходным кодом, призванный сделать программистов более продуктивный.

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

Начало работы

Установка Go

Инструкция по загрузке и установке Go.

Учебное пособие: Начало работы

Краткое руководство Hello, World для начала работы. Узнайте немного о коде Go, инструментах, пакетах и ​​модулях.

Учебник: Создание модуля

Учебник с короткими темами, посвященными функциям, обработке ошибок, массивам, картам, модульному тестированию и компиляции.

Учебное пособие. Начало работы с многомодульными рабочими пространствами

Знакомит с основами создания и использования многомодульных рабочих пространств в Go. Многомодульные рабочие пространства удобны для внесения изменений в несколько модулей.

Учебник: Разработка RESTful API с Go и Gin

Знакомит с основами написания API веб-сервиса RESTful с помощью Go и Gin Web Framework.

Учебное пособие: Начало работы с дженериками

С помощью универсальных шаблонов вы можете объявлять и использовать функции или типы, которые написаны для работы с любым из набора типов, предоставляемых вызывающим кодом.

Учебник

: Начало работы с фаззингом

Фаззинг может генерировать входные данные для ваших тестов, которые могут обнаруживать пограничные случаи и проблемы безопасности, которые вы, возможно, пропустили.

Написание веб-приложений

Создание простого веб-приложения.

Как написать код Go

В этом документе объясняется, как разработать простой набор пакетов Go внутри модуля, и показывает, как использовать команду go для сборки и тестирования пакетов.

Экскурсия по Go

Интерактивное введение в Go в трех разделах. Первый раздел охватывает основной синтаксис и структуры данных; второй обсуждает методы и интерфейсы; а третий представляет примитивы параллелизма Go. Каждый раздел завершается несколькими упражнениями, чтобы вы могли практиковать то, что вы научился. Вы можете отправиться на экскурсию онлайн или установите его локально с помощью:

$ go install golang.org/x/website/tour@latest
 

Это поместит двоичный файл tour в ваш бин каталог.

Использование и понимание Go

Эффективная работа

Документ, который дает советы по написанию понятного идиоматического кода Go. Обязателен к прочтению любому начинающему программисту на Go. Это дополняет тур и спецификацию языка, обе из которых должны быть прочитаны в первую очередь.

Плагины редактора и IDE

Документ, который обобщает часто используемые плагины редактора и IDE с Иди поддержи.

Диагностика

Обобщает инструменты и методологии диагностики проблем в программах Go.

Руководство по сборщику мусора Go

Документ, описывающий, как Go управляет памятью и как извлечь из нее максимальную пользу.

Управление зависимостями

Когда ваш код использует внешние пакеты, эти пакеты (распространяемые как модули) становятся зависимостями.

Фаззинг

Основная страница документации по Go fuzzing.

Доступ к базам данных

Учебник: Доступ к реляционной базе данных

Знакомит с основами доступа к реляционной базе данных с помощью Go и database/sql в стандартной библиотеке.

Доступ к реляционным базам данных

Обзор функций доступа к данным в Go.

Открытие дескриптора базы данных

Вы используете дескриптор базы данных Go для выполнения операций с базой данных. Как только вы откроете дескриптор со свойствами подключения к базе данных, дескриптор представляет соединение пул, которым он управляет от вашего имени.

Выполнение инструкций SQL, которые не возвращают данные

Для операций SQL, которые могут изменить базу данных, включая SQL ВСТАВИТЬ , ОБНОВИТЬ и УДАЛИТЬ , вы используете Методы Exec .

Запрос данных

Для операторов SELECT , которые возвращают данные из запроса, используя Метод запроса или QueryRow .

Использование подготовленных операторов

Определение подготовленного оператора для повторного использования может немного помочь вашему коду. быстрее, избегая накладных расходов на повторное создание оператора каждый раз, когда вы код выполняет операцию с базой данных.

Выполнение транзакций

sql.Tx экспортирует методы, представляющие семантику конкретной транзакции, включая Commit и Rollback , а также методы, которые вы использовать для выполнения общих операций с базой данных.

Отмена выполняемых операций с базой данных

Используя context.Context, вы можете вызовы функций и сервисы вашего приложения перестают работать раньше и возвращать ошибку, когда их обработка больше не нужна.

Управление соединениями

Для некоторых продвинутых программ может потребоваться настройка параметров пула соединений. или работать с подключениями явно.

Предотвращение риска SQL-инъекций

Вы можете избежать риска SQL-инъекций, указав значения параметров SQL как Аргументы функции пакета sql

Модули разработки

Разработка и публикация модулей

Вы можете собрать связанные пакеты в модули, а затем опубликовать модули для использования другими разработчиками. В этом разделе дается обзор разработки и публикации модулей.

Выпуск модуля и рабочий процесс управления версиями

Когда вы разрабатываете модули для использования другими разработчиками, вы можете следовать рабочему процессу, который помогает обеспечить надежную и последовательную работу для разработчиков, использующих модуль. В этом разделе описываются высокоуровневые шаги этого рабочего процесса.

Управление источником модуля

Когда вы разрабатываете модули для публикации для использования другими, вы можете помочь другим разработчикам упростить использование ваших модулей, следуя соглашениям о репозиториях, описанным в этом разделе.

Разработка основного обновления версии

Обновление основной версии может быть очень разрушительным для пользователей вашего модуля, поскольку оно включает критические изменения и представляет собой новый модуль. Подробнее в этой теме.

Публикация модуля

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

Номер версии модуля

Разработчик модуля использует каждую часть номера версии модуля, чтобы сигнализировать о стабильности версии и обратной совместимости. Для каждого нового выпуска номер версии выпуска модуля конкретно отражает характер изменений модуля по сравнению с предыдущим выпуском.

Часто задаваемые вопросы (FAQ)

Ответы на распространенные вопросы о Go.

Ссылки

Комплект документации

Документация по стандартной библиотеке Go.

Командная документация

Документация по инструментам Go.

Спецификация языка

Официальная спецификация языка Go.

Модули Go Артикул

Подробное справочное руководство по системе управления зависимостями Go.

ссылка на файл go.mod

Ссылка на директивы, включенные в файл go. mod.

Модель Go Memory

Документ, определяющий условия, при которых считывается переменная в можно гарантировать, что одна горутина будет отслеживать значения, полученные при записи в та же переменная в другой горутине.

Руководство по вкладу

Участие в Go.

История выпуска

Сводка изменений между выпусками Go.

Кодовые проходы

Экскурсии по программам Го.

  • Первоклассные функции Go
  • Генерация произвольного текста: алгоритм цепи Маркова
  • Совместное использование памяти путем обмена данными

Из блога Go

Официальный блог проекта Go с новостями и подробными статьями команда Go и гости.

Язык
  • JSON-RPC: история интерфейсов
  • Синтаксис объявления Go
  • Отсрочка, паника и восстановление
  • Шаблоны параллелизма в Go: истекает время ожидания, продолжается
  • Go Slices: использование и внутреннее устройство
  • Декодер GIF: упражнение в интерфейсах Go
  • Обработка ошибок и переход
  • Организация Go code
Пакеты
  • JSON и Go — с использованием пакета json.
  • Gobs of data — дизайн и использование пакета gob.
  • Законы отражения — основы пакета отражения.
  • Пакет образа Go — основы пакета образа.
  • Пакет image/draw для Go — основы работы с пакетом image/draw.
Модули
  • Использование модулей Go — введение в использование модулей в простом проекте.
  • Миграция на модули Go — преобразование существующего проекта для использования модулей.
  • Публикация модулей Go — как сделать новые версии модулей доступными для других.
  • Модули Go: v2 и выше — создание и публикация основных версий 2 и выше.
  • Обеспечение совместимости модулей — как обеспечить совместимость модулей с предыдущими младшими версиями/исправлениями.
Инструменты
  • О команде Go — зачем мы ее написали, что это такое, чем это не является и как ею пользоваться.
  • Комментарии Go Doc — написание хорошей программной документации
  • Отладка кода Go с помощью GDB
  • Детектор гонок данных — инструкция к детектору гонок данных.
  • Краткое руководство по ассемблеру Go — введение в ассемблер, используемый Go.
  • С? Идти? Вперед! — связывание с кодом C с помощью cgo.
  • Профилирование программ Go
  • Знакомство с детектором гонок — знакомство с детектором гонок.

Вики

Go Wiki, поддерживаемый сообществом Go, содержит статьи о языке Go, инструментах и ​​других ресурсах.

См. страницу обучения на Wiki. дополнительные ресурсы для обучения Go.

Переговоры

Видео тур по Го

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

Код, который растет с изяществом

Одной из ключевых целей дизайна Go является адаптивность кода; что должно быть легко взять простой дизайн и построить на его основе чистый и естественный способ. В этом выступлении Эндрю Джерранд описывает простой сервер «чат-рулетки», который сопоставляет пары входящих TCP-соединений, а затем использует механизмы параллелизма, интерфейсы и стандартную библиотеку Go для расширения с помощью веб-интерфейса и других функций. В то время как функции программы резко меняются, гибкость Go сохраняет исходный дизайн по мере его роста.

Шаблоны параллелизма Go

Параллелизм — это ключ к проектированию высокопроизводительных сетевых сервисов. Примитивы параллелизма Go (горутины и каналы) предоставляют простые и эффективные средства выражения параллельного выполнения. В этом докладе мы увидим, как сложные проблемы параллелизма можно изящно решить с помощью простого кода Go.

Расширенные шаблоны параллелизма Go

Этот доклад расширяет доклад Go Concurrency Patterns , чтобы глубже погрузиться в примитивы параллелизма Go.

Еще

Посетите сайт Go Talks и вики-страницу, чтобы узнать больше о Go talks.

Документация не на английском языке

См. неанглоязычную страницу в Wiki для локализации документация.

Учебное пособие по

: начало работы с Go

В этом руководстве вы познакомитесь с кратким введением в программирование на Go. Вдоль образом, вы будете:

  • Установите Go (если вы еще этого не сделали).
  • Напишите простой код «Hello, world».
  • Используйте 9Команда 0043 go для запуска вашего кода.
  • Используйте инструмент обнаружения пакетов Go, чтобы найти пакеты, которые вы можете использовать в своих собственных приложениях. код.
  • Вызов функций внешнего модуля.
Примечание: Другие руководства см. Учебники.

Предпосылки

  • Некоторый опыт программирования. Код здесь красивый просто, но это помогает узнать кое-что о функциях.
  • Инструмент для редактирования вашего кода. Любой текстовый редактор, который у вас есть, работать нормально. Большинство текстовых редакторов имеют хорошую поддержку Go. Наиболее популярны VSCode (бесплатно), GoLand (платно) и Vim (бесплатно).
  • Командный терминал. Go хорошо работает с любым терминалом на Linux и Mac, а также PowerShell или cmd в Windows.

Установить Перейти

Просто выполните шаги загрузки и установки.

Напишите код

Начните с Hello, World.

  1. Откройте командную строку и перейдите в свой домашний каталог.

    В Linux или Mac:

    CD
     

    В Windows:

    компакт-диск% ДОМАШНИЙ ПУТЬ%
     
  2. Создайте каталог hello для вашего первого исходного кода Go.

    Например, используйте следующие команды:

    мкдир привет
    компакт-диск привет
     
  3. Включите отслеживание зависимостей для вашего кода.

    Когда ваш код импортирует пакеты, содержащиеся в других модулях, вы управляете эти зависимости через собственный модуль вашего кода. Этот модуль определен файлом go.mod, который отслеживает модули, предоставляющие эти пакеты. Что Файл go.mod остается с вашим кодом, в том числе в исходном коде. репозиторий.

    Чтобы включить отслеживание зависимостей для вашего кода, создав файл go.mod, запустите в команда go mod init , присвоив ему имя модуля, в котором будет находиться ваш код. Имя — это путь модуля модуля.

    В реальной разработке путь к модулю обычно будет репозиторием. место, где будет храниться ваш исходный код. Например, модуль путь может быть github.com/mymodule . Если вы планируете опубликовать ваш модуль для использования другими, путь к модулю должен быть расположение, из которого инструменты Go могут загрузить ваш модуль. Подробнее о имя модуля с помощью пути к модулю, см. Управление зависимости.

    Для целей этого руководства просто используйте пример/привет .

    $ go mod init пример/привет
    go: создание нового go. mod: пример модуля/привет
     
  4. В текстовом редакторе создайте файл hello.go, в котором вы будете писать свой код.

  5. Вставьте следующий код в файл hello.go и сохраните файл.

    основной пакет
    импортировать "фмт"
    основная функция () {
        fmt.Println("Привет, мир!")
    }
     

    Это ваш код Go. В этом коде вы:

    • Объявите основной пакет (пакет — это способ группировки функций и состоит из всех файлов в одном каталоге).
    • Импортируйте популярные фмт пакет, который содержит функции для форматирования текста, включая печать на приставка. Этот пакет является одним из стандартные пакеты библиотек, которые вы получили когда вы установили Go.
    • Реализуйте основную функцию для печати сообщения на приставка. Основная функция выполняется по умолчанию при запуске основной пакет .
  6. Запустите свой код, чтобы увидеть приветствие.

    $ иди беги.
    Привет, мир!
     

    запустить команду это одна из многих команд go , которые вы будете использовать для выполнения задач Идти. Используйте следующую команду, чтобы получить список других:

    $ иди помоги
     

Код вызова во внешнем пакете

Когда вам нужен ваш код, чтобы сделать что-то, что могло бы быть реализовано кто-то еще, вы можете поискать пакет с функциями, которые вы можете использовать в ваш код.

  1. Сделайте свое печатное сообщение немного интереснее с помощью функции из внешний модуль.
    1. Посетите pkg.go.dev и поиск пакета «quote».
    2. Найдите и щелкните пакет rsc.io/quote в результатах поиска. (если вы видите rsc.io/quote/v3 , пока игнорируйте его).
    3. В разделе Documentation под Index обратите внимание на список функций, которые вы можете вызывать из своего кода. Вы будете использовать Перейти к функции .
    4. Обратите внимание, что в верхней части этой страницы указана цитата пакета . включен в модуль rsc.io/quote .

    Вы можете использовать сайт pkg.go.dev, чтобы найти опубликованные модули, пакеты которых имеют функции, которые вы можете использовать в своем собственном коде. Пакеты опубликованы в модули — например, rsc.io/quote — там, где их могут использовать другие. Модули улучшаются новыми версиями с течением времени, и вы можете код для использования улучшенных версий.

  2. В свой код Go импортируйте пакет rsc.io/quote и добавьте вызов к его функции Go .

    После добавления выделенных строк ваш код должен включать следующий:

    основной пакет
    импортировать "фмт"
    импортировать "rsc.io/quote"
    основная функция () {
        fmt.Println(quote.Go())
    }
     
  3. Добавьте новые требования к модулям и суммы.

    Go добавит модуль quote в качестве требования, а также go.sum для использования при аутентификации модуля. Подробнее см. Аутентификация модулей в Go Справочник по модулям.

    $ иди мод аккуратно
    go: поиск модуля для пакета rsc.io/quote
    go: нашел rsc.io/quote в rsc.io/quote v1.5.2
     
  4. Запустите свой код, чтобы увидеть сообщение, сгенерированное вызываемой функцией.
    $ иди беги.
    Не общайтесь, делясь памятью, делитесь памятью, общаясь.
     

    Обратите внимание, что ваш код вызывает функцию Go , печатающую умное сообщение о связи.

    Когда ты побежал go mod tidy , он нашел и скачал Модуль rsc. io/quote , содержащий импортированный пакет. По умолчанию загружается последняя версия — v1.5.2.

Напишите еще код

Благодаря этому краткому введению вы установили Go и узнали некоторые основы. Чтобы написать еще немного кода с другим учебником, взгляните на Создайте модуль Go.

Для чего действительно хорош язык программирования Go (Golang)?

Узнайте о сильных и слабых сторонах, вариантах использования и будущих направлениях популярного языка программирования Google.

старший писатель, Информационный мир |

Павел Червинский (СС0)

За более чем десятилетие своего пребывания в дикой природе язык Google Go, также известный как Golang, с версией 1.18, выпущенной по состоянию на март 2022 года, превратился из любопытства альфа-компьютерщиков в испытанный в боях язык программирования, стоящий за одними из самых популярных в мире языков. важных облачных проектов.

Почему Go выбрали разработчики таких проектов, как Docker и Kubernetes? Каковы определяющие характеристики Go, чем он отличается от других языков программирования и какие проекты он лучше всего подходит для создания? В этой статье мы рассмотрим набор функций Go, оптимальные варианты использования, упущения и ограничения языка, а также то, куда Go может двигаться дальше.

Язык Go небольшой и простой

Go, или Golang, как его часто называют, был разработан сотрудниками Google — главным образом давним гуру Unix и выдающимся инженером Google Робом Пайком, — но, строго говоря, это не «проект Google». Скорее, Go разрабатывается как проект с открытым исходным кодом под руководством сообщества, возглавляемый руководством, у которого есть твердое мнение о том, как следует использовать Go и в каком направлении должен развиваться язык.

Go должен быть простым в освоении, простым в работе и легким для понимания другими разработчиками. Go не имеет большого набора функций, особенно по сравнению с такими языками, как C++. Go напоминает C по своему синтаксису, что делает его относительно простым для давних разработчиков C. Тем не менее, многие функции Go, особенно возможности параллелизма и функционального программирования, восходят к таким языкам, как Erlang.

Как C-подобный язык для создания и поддержки межплатформенных корпоративных приложений всех видов, Go имеет много общего с Java. А в качестве средства обеспечения быстрой разработки кода, который может выполняться где угодно, вы можете провести параллель между Go и Python, хотя различий гораздо больше, чем сходства.

В языке Go каждый найдет что-то для себя

В документации Go Go описывается как «быстрый, статически типизированный, компилируемый язык, который выглядит как интерпретируемый язык с динамической типизацией». Даже большая программа на Go скомпилируется за считанные секунды. Кроме того, Go позволяет избежать большей части накладных расходов, связанных с включением файлов и библиотек в стиле C.

Go упрощает жизнь разработчика несколькими способами.

Go удобен

Go сравнивают с языками сценариев, такими как Python, по его способности удовлетворять многие общие потребности программирования. Некоторые из этих функций встроены в сам язык, например «горутины» для параллелизма и потокового поведения, в то время как дополнительные возможности доступны в стандартных пакетах библиотеки Go, таких как http-пакет Go. Как и Python, Go предоставляет возможности автоматического управления памятью, включая сборку мусора.
В отличие от языков сценариев, таких как Python, код Go компилируется в быстро исполняемый собственный двоичный файл. И в отличие от C или C++, Go компилируется очень быстро — достаточно быстро, чтобы работа с Go больше напоминала работу с языком сценариев, чем с компилируемым языком. Кроме того, система сборки Go менее сложна, чем у других компилируемых языков. Для создания и запуска проекта Go требуется несколько шагов и небольшая бухгалтерия.

Go работает быстро

Двоичные файлы Go работают медленнее, чем их аналоги C, но разница в скорости для большинства приложений незначительна. Производительность Go не уступает C для подавляющего большинства задач и, как правило, намного выше, чем у других языков, известных своей скоростью разработки (например, JavaScript, Python и Ruby).

Go является переносимым

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

Go совместим

Go обеспечивает все вышеперечисленное без ущерба для доступа к базовой системе. Программы Go могут взаимодействовать с внешними библиотеками C или выполнять собственные системные вызовы. В Docker, например, Go взаимодействует с низкоуровневыми функциями Linux, контрольными группами и пространствами имен, чтобы работать с контейнерами.

Go широко поддерживается

Цепочка инструментов Go находится в свободном доступе в виде бинарного файла для Linux, MacOS или Windows или в виде контейнера Docker. Go включен по умолчанию во многие популярные дистрибутивы Linux, такие как Red Hat Enterprise Linux и Fedora, что несколько упрощает развертывание исходного кода Go на этих платформах. Поддержка Go также сильна во многих сторонних средах разработки, от Microsoft Visual Studio Code до ActiveState Komodo IDE.

Где язык Go работает лучше всего

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

Go лучше всего подходит для разработки следующих типов приложений.

Облачная разработка

Параллелизм и сетевые функции Go, а также его высокая степень переносимости делают его хорошо подходящим для создания облачных приложений. Фактически, Go использовался для создания нескольких краеугольных камней облачных вычислений, включая Docker, Kubernetes и Istio.

Услуги распределенной сети

Сетевые приложения живут и умирают за счет параллелизма, и встроенные в Go функции параллелизма — главным образом горутины и каналы — хорошо подходят для такой работы. Следовательно, многие проекты Go предназначены для сетей, распределенных функций и облачных сервисов: API, веб-серверов, минимальных фреймворков для веб-приложений и т. п.

Утилиты и автономные инструменты

Программы Go компилируются в двоичные файлы с минимальными внешними зависимостями. Это делает их идеально подходящими для создания утилит и других инструментов, поскольку они быстро запускаются и могут быть легко упакованы для дальнейшего распространения. Одним из примеров является сервер доступа под названием Teleport (среди прочего, для SSH). Teleport можно быстро и легко развернуть на серверах, скомпилировав его из исходного кода или загрузив готовый двоичный файл.

Языковые ограничения Go

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

Одной из давних жалоб было отсутствие универсальных функций, которые позволяют функции принимать множество различных типов переменных. В течение многих лет команда разработчиков Go возражала против добавления в язык дженериков на том основании, что им нужен был синтаксис и набор поведений, которые дополняли бы остальную часть Go. Но начиная с Go 1.18, выпущенного в начале 2022 года, язык теперь включает синтаксис для дженериков. Урок, который следует извлечь, заключается в том, что Go редко добавляет основные функции и только после тщательного рассмотрения, чтобы лучше сохранить широкую совместимость между версиями.

Другим потенциальным недостатком Go является размер создаваемых двоичных файлов. Бинарные файлы Go по умолчанию компилируются статически, а это означает, что все, что нужно во время выполнения, включено в бинарный образ. Этот подход упрощает процесс сборки и развертывания, но за счет простого «Привет, мир!» весит около 1,5 МБ в 64-битной Windows. Команда Go работала над уменьшением размера этих двоичных файлов с каждым последующим выпуском. Также можно уменьшить двоичные файлы Go с помощью сжатия или путем удаления отладочной информации Go. Этот последний вариант может работать лучше для автономных распределенных приложений, чем для облачных или сетевых служб, где отладочная информация полезна в случае сбоя службы на месте.

Еще одна разрекламированная функция Go, автоматическое управление памятью, может рассматриваться как недостаток, поскольку сборка мусора требует определенных накладных расходов на обработку. Go не обеспечивает ручное управление памятью, а сборка мусора в Go подвергается критике за то, что она плохо справляется с нагрузками на память, возникающими в корпоративных приложениях.

Тем не менее, каждая новая версия Go улучшает функции управления памятью. Например, в Go 1.8 значительно сократилось время задержки при сборке мусора. У разработчиков Go есть возможность использовать ручное выделение памяти в расширении C или с помощью сторонней библиотеки ручного управления памятью, но большинство разработчиков Go предпочитают нативные решения этих проблем.

Культура программного обеспечения, связанная с созданием богатых графических интерфейсов для приложений Go, таких как настольные приложения, все еще разбросана.

Большинство приложений Go являются инструментами командной строки или сетевыми службами. Тем не менее, различные проекты работают над созданием богатых графических интерфейсов для приложений Go. Существуют привязки для фреймворков GTK и GTK3. Другой проект предназначен для предоставления платформенных пользовательских интерфейсов, хотя они основаны на привязках C и не написаны на чистом Go. А пользователи Windows могут попробовать ходить. Но в этой области не появилось явного победителя или надежной долгосрочной ставки, а некоторые проекты, такие как попытка Google создать кроссплатформенную библиотеку графического интерфейса, ушли на второй план. Кроме того, поскольку Go по своей конструкции не зависит от платформы, маловероятно, что какой-либо из них станет частью стандартного набора пакетов.

Хотя Go может взаимодействовать с собственными системными функциями, он не предназначен для создания низкоуровневых системных компонентов, таких как ядра, драйверы устройств или встроенные системы. В конце концов, среда выполнения Go и сборщик мусора для приложений Go зависят от базовой ОС. (Разработчики, заинтересованные в передовом языке для такой работы, могут обратить внимание на язык Rust.)

Будущее языка Go

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

Опрос разработчиков Go в 2021 году показал, что пользователи Go в целом довольны тем, что предлагает язык, но также отметили, что есть много возможностей для улучшения. Основными областями, в которых пользователи Go хотели улучшить, были управление зависимостями (постоянная проблема в Go), диагностика ошибок и надежность, при этом такие проблемы, как память, использование ЦП, размеры двоичных файлов и время сборки, были намного ниже.

Большинство языков тяготеют к основному набору вариантов использования. За десять лет существования Go его нишей стали сетевые сервисы, где он, вероятно, продолжит расширять свое присутствие. По большому счету, основным вариантом использования языка было создание API или RPC-сервисов (49).%), за которыми следуют обработка данных (10%), веб-сервисы (10%) и приложения CLI (8%).

Еще одним признаком растущей привлекательности языка Go является то, сколько разработчиков выбирают его после оценки. 75% опрошенных, которые рассматривали возможность использования Go для проекта, выбрали этот язык. Из тех, кто не выбрал Go, лучшими альтернативами были Rust (25%), Python (17%) и Java (12%). Каждый из этих языков нашел или находит другие ниши: Rust для безопасного и быстрого системного программирования; Python для прототипирования, автоматизации и склеивания кода; и Java для давних корпоративных приложений.

Пока неясно, насколько скорость и простота разработки помогут Go в других случаях использования или насколько глубоко Go проникнет в корпоративную разработку.