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


for – range по указателю

С циклом for — range связан важный момент — операнд range копируется во временную переменную, которая уже используется для обхода.

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

for i, temp := range &weekTemp {
    fmt.Println(i, temp)
} 

Источник – Массивы в Go.


Возвращаемые функцией значения могут иметь имя

Список возвращаемых значений имеет тот же синтаксис, что и список параметров. Например, можно написать коротко:

func foo() (x, y, z int) 

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

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

Вот функция, которая находит индекс буквы в строке и возвращает вторым аргументом false, если буква не найдена:

func Index(st string, a rune) (index int, ok bool) {
    for i, c := range st {
        if c == a {
            return i, true
        }
    }
    return // вернутся значения по умолчанию
} 

Источник – Функции


Функция init()

В базовом синтаксисе языка также описана вот эта функция:

func init() { … } 

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

Служат эти функции для создания окружения, необходимого пакету для корректной работы.

Вот простой пример:

var name, surname string
 
func init() {
    name = "John"
}
func init() {
    if surname == "" {
        surname = "Doe"
    }
}
func main() {
    fmt.Println("Hello " + name + " " + surname)
} 

Источник – Функции


Порядок импорта

Рассмотрим подробнее, как выполняется импорт пакетов.

  1. При компиляции программы компилятор начинает с пакета main. Если в main есть импорты каких-либо пакетов, то он переходит к ним и компилирует их, до тех пор пока не скомпилируются все необходимые пакеты для сборки программы.
  2. Затем компилятор компилирует пакет main и собирает основное приложение, а далее в процессе выполнения программы произойдёт следующее: 1. В том порядке, в котором пакеты были проимпортированы, будут инициализироваться переменные пакета. 2. После будут выполнены функции init() внутри каждого пакета. Функций init() может быть несколько, и они выполнятся в том порядке, в котором были объявлены. 3. И после их выполнения наступит очередь функции main.

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

Источник – Пакеты и импорты в Go


Пустой импорт

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

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

import _ "embed"
 
//go:embed assets/insert.sql
var queryInsert string 
 
//go:embed assets/header.html
var header string

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

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

Источник – Пакеты и импорты в Go



📂 Go | Последнее изменение: 27.08.2024 23:49