Установка golang 1.8

По дефолту в убунту-подобных системах до сих пор ставится golang 1.6.
Для установки рекомендую воспользоваться следующим PPA:
sudo add-apt-repository ppa:longsleep/golang-backports 
sudo apt-get update 
sudo apt-get install golang-go

Panic, recover в golang

Несмотря на наличие мануала непросто досконально понять, как работают конструкции panic и recover.

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

Обработать panic может помочь ф-ция recover. Ф-ция сама по себе бессмысленна и использоваться должна в следующем фрагменте кода:
defer func() {
    if r := recover(); r != nil {
        // любые действия при возникновении ошибки
    }
}()


Как видим recover вызывается внутри отложенной (defer) конструкции.
Код defer вызывается при завершении ф-ции, в которой он описан. При чем вызовется он в любом случае: в случае рядового завершения ф-ции; при панике паники; в случае завершения всей программы после SIGKILL.

Recover похож на catch, но всё же не дотягивает до него, т.к. после catch можно продолжить выполнение ф-ции как угодно, например вернуть какое-то другое значение (вызвать return). Recover же даёт возможность выполнить некоторое действие, но повлиять на возвращаемое ф-цией значение уже не может, т.к. он выполняется recover в контексте defer.

Интересно, что ф-ция, внутри которой сработал defer-recover, вернёт дефолтное значение своего типа. Например, если ф-ция bool, то false. Если int, то 0. Если указатель, то nil.

Пример ниже показывает то, что ф-ция типа *string после recover вернёт nil, как бы не хотелось получить указатель на 456.
s:= func() *string {
    defer func() {
        if r := recover(); r != nil {
            d := "456"
            return &d
        }
    }()
    panic("error");
    d := "123"
    return &d
}()

log.Printf("%+v\n", s) // выведет nil

Парсинг json в golang

Для парсинга cуществует стандартный модуль json и конкретно ф-ция Unmarshal.
func Unmarshal(data []byte, v interface{}) error


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

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

var s struct{ Id int }
// Парсим пустой json в структуру с числовым полем
json.Unmarshal([]byte(`{}`), &s)

// Выведет 0, на самом деле, как мы видели, 0 не передавался
log.PrintLn(s.Id)


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

var s struct{ Id *int }
// Парсим пустой json в структуру с числовым полем
json.Unmarshal([]byte(`{}`), &s)

if s.Id == nil {
   // Ничего не передавалось
}


Для ускорения массовой генерации json для структур можно использовать модуль ffjson, повторяющий интерфейс модуля json.
ffjson на этапе компиляции генерирует код парсинга каждой структуры и использует этот код в реалтайме, обходясь без более долгоработающего модуля reflect. Плюсы модуля — в 2-3 раза более быстрая генерация. Минусы — больший бинарник.