kbook


Project maintained by atilla777 Hosted on GitHub Pages — Theme by mattgraham
Главная страница
Go

Go

Структура кода

Простое приложение

package main // в приложении должен быть главный пакет

import "fmt" // импорт используемых модулей (в них определены используемые функции)

// в приложении должна быть главная функция
func main() {
fmt.Println("Привет, В.!")
}

Пакеты

Пакеты в go это исходные коды библиотек, используемых в приложении. Сторонние пакеты (полученные из Интернета) размещаются (при выполнении go get) в папке src рабочего каталога, текущего проекта go.

Установка пакета

Команды необходимо запускать

go get пакет

Пример

go get github.com/cavaliercoder/grab

Импорт такого пакета

"github.com/cavaliercoder/grab"

Переменные

Переменные записываются в low CamelCase

nameName
Объявление и присвоение переменной :=
x := значение

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

Объявление и присвоение нескольких переменных
x, y := значение1, значение2

Константы

Объявление константы и присвоение ей значения

const Константа тип = значение
Автоинкремент (iota)

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

const (
	a = iota 	// 0
	b = iota 	// 1
	с = iota 	// 2
)

можно записать и так

const (
	а = iota 	// 0
	b = iota 	// 1
	с = iota 	// 2
)

или с упращенным синтаксисом (ради этого, собственно, всё и затевалось - удобный сопсоб задать перечисления)

const (
	statusA = iota 		// 0
	statusB 		// 1
	statusC 		// 2
)

Начинать можно не с 0, также можно пропускать значения

const (
	a = iota + 1 	// 1 так как iota начинается с 0
	_ 		// тут было бы 2
	b 		// b = 3
)

Условные выражения

if выражение {
	код
} else {
	код
}

Обработка исключений

Вызов исключения
panic значение
Выполнениея действия перед возвратом из функции
defer connection.close

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

Импорт необходимого пакета

import "log"

Вывод сообщения в os.Stdout

log.Println("сообщение")
Вывод сообщения в os.Stderror и завершение работы программы
log.Fatal("сообщение")

Прочее

Запуск внешней программы
cmd := exec.Command(result1)
cmd.start()

Весь код приложения (включая библиотеки) компилируется в один файл программы - у такого исполняемого файла не внешних зависимостей

"строка с \n"
`строка как есть`
'символ'

У объявленных, но не проинициализированных переменных есть значение по умолчанию

Capacity всегда в 2 раза больше чем (про запас) его длина. При добавлении в слайс создается новый массив.

cap(слайс)
Объеденить слайсы
append(слайс1,слайс2...)
Создать слайс заданной дины
make([]тип, длина)

Пример (при добавлении в такой слайс элемента, он будет добавлен 11м)

make([]int, 10)
Создать слайс заданной дины и емкости (за счет резервирования (расходования) памяти повышается производительность - не надо будет создавать новый массив при добавлении новых элементов сверх заданной длины слайса)
make([]тип, длина, емкость)

Для операций с разными типами (включая константы) типы нужно приводить - вызывать функцию имя которой равно имени типа, к которому приводится значение int(значение)

Структуры

Объявление типа структура
type Структура struct {
	имя1 тип1
	имяN типN
}
Инициализация структуры
var s Структура

или

s := Структура{поле1: значение1, полеN: значениеN}

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

sruct Структура  {
	имя1 int64
	имя2 int
	имя3 bool
}

Методы структуры

Методы - это функции, связанные со структурами (их приемниками являются структуры)

func (приёмник *Структура) метод(параметр тип) тип_результата {
	код с приёмником (структурой)
}
Объявление анонимной (без имени типа) структуры
struct {
	имя1 тип1
	имяN типN
} {
	имя1 значение1
	имяN значениеN
}

Если типы и имена переменных двух структур совпадают, то при сравнении, присвоении и т. п. переменных с типами таких структур требуется явное приведение типов. ```go var struct one { first int } var struct two { first int }

a := one { i 1 }

b := two { i 2 } a = one(b)

Если одна из таких переменных является структурой с анонимным типом, то компилятор сам выполнит неявное приведении типов.
```go
var struct one {
	first int
}
a := one {
	i 1
}

b := struct {
	i 2
}
a = b

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

Функции и методы

Функция модуля (доступна только в этом модуле)
функция ...
Функция которая может вызываться из модуля
Функция ...
Определение функции
func функция(параметр Тип) тип_возвращаемого_значения {
	код
	return значение // возврат значения
}
Вызов функции
функция(параметр)
Отложенный вызов функций

Вызванная с помощью defer функция будет выполнена последней текущей функции (функция внутри которой вызывается отложенная)

defer функция()

defer используется для:

  • закрытия файлов (других объектов ресурсов, требующих закрытия) в конце выполнения текущей функции
  • перехвата и обработки исключений (defer функции вызываются даже если были исключения)

    Указатели

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

    Передача параметра в функцию по значению

    func функция(тип параметр) {
      код
    }
    

    Передача параметра в функцию по ссылке (указателю)

    func функция(тип *параметр) {
      код
    }
    переменная := значение
    функция(&переменная)
    

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

Интерфейсы

Интерфейсы используются для реализации в go утиной типизации – если что-то крякает как утка (читай, реализует метод) то это и есть утка.

То есть имея (реализуя) несколько интерфейсов одна и таже структура может относится к нескольким утиным типам.

Или разные структуры могут реализовывать один интерфейс (иметь один утиный тип) и быть его приёмником.

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

Определение интерфейса

После определения интерфейса

Для производительности в функцию лучше определять не с аргументами, а с ссылками -аргумент *Тип. Это позволяет избежать копировании данных (читай – расход памяти) при передаче аргументов.

Компиляция

Скомпилировать безоконное приложение
go build программа.go -ldflags -H=windowsgui
Уменьшить размер исполняемого файла за счет исключения отладочной информации
-ldflags="-s -w"
Уменьшить размер исполняемого файла с помощью UPX за счет его сжатия (не рекомендуется для часто запускаемых файлов, так как перед запуском каждый раз выполняется декомпрессия)
upx --brute приложение
Динамические библиотеки

По умолчанию компиляция в go происходит с использованием динамически подгружаемых библиотек на С (функционал CGO). В частности такой штатаный пакет как net может использовать динаические библиотеки (libc) для разрешения имен (выбор способа разрешения имен - с использованием CGO или без, выполняется на основе провекрки нескольких условий, в том числе связанных с тем, какая ОС используется). Также CGO могут использовать сторонние пакеты (sqlite3). По умолчанию компиляция выполняется с CGO_ENABLED=1, то есть с динамической линковкой. Можно узнать, какие динамические библитоеки использует скомпилированная go программа

ldd программа

Если такие библиотеки (CGO) в приложении не используются то можно скомпилировать go приложение без каких либо зависимостей (статическая линковка). Это хороршо подойдет для приложения, которое будет запускаться в пустом (form scratch) docker контейнере, где нет никаких библиотек,которые можно динамически подключать.

CGO_ENABLED=0 go build исходник.go -o программа

Можно явно сказать компилятору, что необходимо использовать только GO функцианал библитеки net, без внешних зависимостей

CGO_ENABLED=0 go build -tags netgo -a -v исходник.go -o программа

Если без динамических бибилиотек не обойтесь, а приложение надо запускать в docker контейнере где нет библитек,то можно скопироват в этот образ необходимые библитеки (например, из промежуточного docker образа).