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 реинициализуруется каждый раз, когда в коде встречается ключевое слово 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"
log.Println("сообщение")
log.Fatal("сообщение")
cmd := exec.Command(result1)
cmd.start()
Весь код приложения (включая библиотеки) компилируется в один файл программы - у такого исполняемого файла не внешних зависимостей
"строка с \n"
`строка как есть`
'символ'
У объявленных, но не проинициализированных переменных есть значение по умолчанию
name := "Ivan"
str := "Hello %s !"
interpolated_str := fmt.Sprintf(str, name)
Длина слайса
len(слайc)
Capacity (емкость) слайса - длина массива на котором лежит слайс.
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 --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 образа).