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

Я постараюсь обобщить информацию, которая показалась мне наиболее интересной.

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

Зависимости

Go был создан Робертом Гриземером, Робом Пайком и Кеном Томпсоном из Google. Одной из его целей было сократить время компиляции.
Работая с C, они увидели, что зависимости можно улучшить.
В больших приложениях было трудно определить, какие из них больше не нужны. В масштабе эти накладные расходы превратились в проблему.

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

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

Синтаксис

Идея заключалась в том, чтобы создать простой и чистый синтаксис.

Объявление переменной

Первое, что бросается в глаза, это объявление переменных.

x := "Foo"

Это просто синтаксический сахар, обозначающий объявление и инициализацию. Это эквивалентно

var x = "Foo"

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

var x string

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

Пример:

func main(int, []string) int {} // Go
int main(int, char *[])         // C

Это имеет значение, когда есть вложенные функции.

Go был разработан таким образом, чтобы облегчить чтение. Он разработан в стиле слева направо, тогда как C разработан по спиральному правилу.

Общественный / частный

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

func Sqrt(x float64) float64 {...}
func pow(x int) int {...}

В этом примере Sqrt является общедоступным, а pow — частным. Это работает для всего: переменных, функций, методов и так далее.

Петли

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

for i := 0; i < 100; i++ {
    // Default loop
}
for i < 100 {
    // Without declaration
}
for {
    // Infinite loop
}
for i, v := range some_array {
    // Loop with enumeration
}

Ошибки

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

Пример как это выглядит:

file, err := os.Open("file")
if err != nil {
    log.Fatal(err)
}

ООП

Композиция важнее наследования

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

Интерфейсы и полиморфизм

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

type geometry interface {
    area() float64
}

затем создайте тип rectangle с area(), который возвращает тот же тип

type rectangle struct {
    width, height float64
}
func (r rectangle) area() float64 {
    return r.width * r.height

затем rectangle неявно реализует геометрию, поэтому вы можете сделать:

func calculate_area(g geometry) float64 {
    return g.area()
}

Это одна из самых интересных функций Golang для меня прямо сейчас. Это заставляет вас думать немного иначе, чем при программировании на языке с наследованием.

Инкапсуляция

Это обеспечивается капитализацией переменных и методов. Нет необходимости в protected, так как нет наследования.

параллелизм

Самая интересная для меня тема. Мне нравится идея написания параллельных программ. В Python это довольно подавляющее. Есть интересный пост в блоге, написанный Армином Ронахером об AsyncIO.

В Go он кажется более элегантным, более простым для понимания и более эффективным.

Горутины

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

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

// Version: 1
func fetch_numbers() []int {
    numbers := make([]int, 10, 10)
    for i := 0; i < 10; i++ {
        time.Sleep(1 * time.Seconds) // 1s blocking IO
        numbers[i] = rand.Intn(1000)
    }
    return numbers
}
func main() {
    numbers := fetch_numbers()
    for _, v := range numbers {
        fmt.Println(v) // Print or Calculation
    }
}

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

Запуск fetch_number() в Gorutine ничего не улучшает. Чтобы использовать горутины, нам нужен способ общения между ними.

каналы

Горутины могут общаться с помощью каналов или мьютексов. В этом примере я буду использовать канал.

Шанель похожа на трубу, из нее можно читать или посылать через нее элементы.

// Version: 2
func fetch_numbers(channel c) {      // Takes channel
    for i := 0; i < 10; i++ {
        time.Sleep(1 * time.Seconds) // 1s blocking IO
        c <- rand.Intn(1000)         // Feeds channel with number
    }
    close(c)                         // Closes channel
}
func main() {
    c := make(chan int)    // Creates channel of integers
    go fetch_numbers(c)    // Runs fetch_numbers in new gorutine
                           // passing channel
    for _, v := range c {  // Iterates over received numbers from
                           // channel
        fmt.Println(v)     // Print or Calculation
    }
}

Версия 2 лучше, потому что позволяет Go переключать горутины, когда fetch_numbers() блокируется. Он может вернуться к итерации (получатель) в функции main() и продолжить печать. Так как у нас есть приемник, который ждет следующего элемента из канала, важно закрыть его.

Вот версия с некоторыми улучшениями.

// Version 3
func fetch_numbers() chan int {  // returns a channel
    c := make(chan int)          // creates channel inside a func
    go func() {                  // runs gorutine insinde a func
        for i := 0; i < 10; i++ {
            time.Sleep(1 * time.Second)
            c <- rand.Intn(1000)
        }
        close(c)
    }()
    return c
}
func main() {
    c := fetch_numbers()
    for v := range c {
        fmt.Println(v)
    }
}

Здесь в основной функции нам не нужно создавать канал. Его может вернуть функция fetch_numbers(), которая занимается созданием горутины.

Выглядит намного чище.

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

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

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

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

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

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

Дедлайн 7.11.2018 (12 дней)