Go за 20 часов

Categories: dev

Решил потратить выходные с пользой, и вернутся к изучению Go. У меня было примерно 20 часов, за которые я успел изучить все что мне нужно и написал довольно простой mvc-like фреймворк. Начем по порядоку.

До этого момента я пробовал Go около 3х лет назад, непомню какая была версия, но помню о Go тогда только начали узнавать. О самом языке тогда небыло ничего ясно кроме того что он от Google. И что многие известные люди успешно разрабатывают на Go например Brad Fitzpatrik

Непросто так упоминаю Бреда Фитцпатрика, а потому что первое приложение на Go в исходники которого я смотрел был Camilstore - персональное хранилище с синхронзацией. На тот момент это казалось непостижимо сложными и трудно изучаемым, прошло время и про Go стали говорить больше и не только в “долине”.

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

Вопросы которые для меня важны когда я изучаю новый ЯП

  • Документация
  • Наличие готовых библиотек и рабочих проудктов
  • Наличие комьюнити
  • Наличие качественной библиотеки для работы с БД
  • Быстрое понимание
  • Приятный синтаксис

Примерно через 20 часов я получил положительные ответы на свои вопросы

Что такое язык Go ?

Это компилируемый язык со статической типизацией, предназначенный для реализации высокопроизводительных паралельных вычислений, в нем есть garbage collector, memory safety - безопасный доступ к памяти, а также CSP который как раз используется для описания паралельных вычислейний. Go похож на C но с улучшениями в сторону понимания, простоты и безопасности.

package main

import "fmt"

func main() {
    fmt.Println("hello world")
}

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

А ниже немного интересных моментов языка.

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

func Nice(first string, shits ...string) int64 {
    
}

Struct / Структуры

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

// A struct with 6 fields.
struct {
	x, y int
	u float32
	_ float32 
	A *[]int
	F func()
}

Пример встаривания структур

type Animal struct {
    Name string
}

type Cat struct {
    Animal
    Breed string
}
    

Структура также может быть определена с использованием тега Подбронее

struct {
	camelCaseString  uint64 `json:"came_case_string"`
	serverIP6 uint64 `json:"server_ip6"`
}

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

Interfaces / Интерфейсы

type Shape interface {
    area() float64
}
        

Channels / Каналы

Канал предоставляет механизм конкуретного вызова функций. С помощью его можно оргазовывать пайплайны (pipelines)

chan T          // can be used to send and receive values of type T
chan<- float64  // can only be used to send float64s
<-chan int      // can only be used to receive ints

Пример работы каналов (взял отсюда)

package main

import "fmt"
import "time"

func doIt(done chan bool) {
    	fmt.Print("working...")
    	time.Sleep(time.Second)
    	fmt.Println("done")
	
        // send value to channel
    	done <- true
}

func main() {
        // We're creating channel and
        // starting doIt function as gorouine
    	done := make(chan bool)
    	go doIt(done)

        // reading from channel with `<-` blocks program until
        // we receive value after one second in `doIt` function
    	a := <-done
    	fmt.Println(a)
    }

Это очень простой пример каналов, больше примеров ищите по ссылкам в конце поста.

Goroutines

Отложенные процедуры Пример

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

// A _goroutine_ is a lightweight thread of execution.

package main

import "fmt"

func f(from string) {
    for i := 0; i < 3; i++ {
        fmt.Println(from, ":", i)
    }
}

func main() {

    // Suppose we have a function call `f(s)`. Here's how
    // we'd call that in the usual way, running it
    // synchronously.
    
    f("direct")

    // To invoke this function in a goroutine, use
    // `go f(s)`. This new goroutine will execute
    // concurrently with the calling one.
    
    go f("goroutine")

    // You can also start a goroutine for an anonymous
    // function call.
    
    go func(msg string) {
        fmt.Println(msg)
    }("going")

    // Our two function calls are running asynchronously in
    // separate goroutines now, so execution falls through
    // to here. This `Scanln` code requires we press a key
    // before the program exits.
    
    var input string
    fmt.Scanln(&input)
    fmt.Println("done")
}

Кроме goroutines в Go есть инструкция defer с помощью которой можно выполнять функции в конце заверешния работы текущего scope функции. Пример работы defer

Тесты

Для тестирования в Go существует стандартная библиотека testing

Простой пример с использованием стороннего пакета для assertion

Нужно обратит внимание что тесты в Go должны находится в файлах с суффиксом test soulkitchen_test.go а методы внутри дожныы иметь префикс Test

package soulkitchen

import (

	"github.com/stretchr/testify/assert"
	"testing"
)

func TestNew(t *testing.T) {

	assert := assert.New(t)
	assert.Nil(nil)
}

Нестал писать скольконибудь подробное тестирование, но простейший пример привел. Запуск тестов в данном случае это выполнение в корне проекта команды:

go test

которая запустит все тесты в текущей директрии

go test
PASS
ok  	github.com/noroot/soulkitchen	0.014s

Подробнее про тесты

Кроме тестов в Go существуют бенчмарки (Benchmarks) которые позволяют понять насколько быстро работают написанные механизмы. Чтобы воспользоваться бенчмарками нужно сделать особо обьявленный метод.

func BenchmarkHello(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fmt.Sprintf("hello")
    }
}
    

Бенчмарки запускаются с помощью команды

go test -bench .

В качестве параметра к ключу bench указывается регулярное выражение маска для того чтобы определить какие бенчмарки запускать Подробнее про возможные параметры запуска здесь

Coding style

Для соблюдения конвенций по стилю форматирования файлов, в Go предусмотрена специальная утилита gofmt которая форматирует исходный код.

gofmt src/main.go

В Go для отступов принята табулция шириной 8.

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

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

godoc -http=:6060

Пример

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

package main
import (
	"io/ioutil"
	"log"
	"net/http"
)

func Future(f func() (interface{}, error)) func() (interface{}, error) {
    var result interface{}
    var err error

    c := make(chan struct{}, 1)
    go func() {
        defer close(c)
        result, err = f()
    }()

    return func() (interface{}, error) {
        <-c
        return result, err
    }
}


func main() {
	
	url := "http://labs.strava.com"
	future := Future(func() (interface{}, error) {
		resp, err := http.Get(url)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		return ioutil.ReadAll(resp.Body)
	})
	
	// do many other things
	
	b, err := future()
	body, _ := b.([]byte)
	
	log.Printf("response length: %d", len(body))
	log.Printf("request error: %v", err)
}

Подсмотрел здесь

Впечателния

Ощущения такие что нашел язык на котором надо программировать, а не просто собирать что-то из кубиков. Oldschool ощущения подобные те которые можно испытывать программируя на C при этом код не сильно сложнее чем Nodejs.

Про производительсноть, - она очень высокая, особенно в сравнении ruby, php и python, но хочется предостеречь от всяког рода холиваров потомучто в итоге нужны нормальные полноценные бенчмарки, а их как всегда нужно делать или как минимум проверять самому.

Вначале заметки я писал что взялся за реализацию MVC, да это довольно просто, но начинает почти сразуже обрастать типовыми задачами, поэтому имеет смысл взять готовый web-фреймворк которых на Go полно, а особенно много мини-фреймворков котоырй реализуют routing и handlers аналогично expressjs.

Напоследок вставлю список проектов написанных на Go в нем довольно много интересного например Docker. А это как минмум значит что Docker это next big thing к которой стоит пресмотреться.

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

Ссылки

Бенчмарк Go и других

Go introduction by Toptal

Курируемый список библиотек и инструментов на Go

Много примеров типовых решений на Go

Русифицированная книга про Go

Стандартные паттерны в Go

Много примеров на Go

Типовые ошибки в Go

Хороший пример про каналы и CPU

Пример каналов

Gorm - Лучшая SQL ORM на Golang


No comments here yet Write here gently

No webmentions were found.

Comments powered by Talkyard.