[Заметка] Заметки по Go
Внимание
Основное
- Всё неиспользуемое является ошибкой компиляции.
- Выполнение программы происходит в функции
main
. - Функция
init
вызывается доmain
(то естьinit
из всех пакетов, а потомmain
). - Область видимости - внутри блока и выше.
$GOPATH
структураbin/
pkg/
src/
Пакеты
- Пакеты лежат в соответствующих папках.
- Файлы могут оканчиваться на
_darwin
,_linux
,_windows
. _test
тест кейсы.- Импорт в рамках файла, в котором импортируется.
Константы
- Принято в
UpperCamelCase
. - Многострочные в скобках принимают значение предыдущей.
- Спец указатель
iota
.
const Val = 1
const (
Val1 = 2
Val2 // eq prev Val1
)
const (
Val3 = iota // == 0
Val4 // iota++ == 1
_ // пропуск, но iota++
Val5 // iota++ == 3
)
const (
Val6 = iota * 3 // == 0
Val7 // iota++ == 3
Val8 // iota++ == 6
)
Константы пакета, начинающиеся с маленькой буквы доступны только внутри пакета, с большой извне тоже.
Переменные
- Тип не может меняться.
- Объявляются через var с указанием типа после.
- Можно объявить без var и типа через
:=
но только в функциях.
var val bool = true
var g, m int = 1, 2
var val1, val2 int // не инициализированы
func main() {
val3 := 5
fmt.Println(val3)
}
Переменные пакета, начинающиеся с маленькой буквы доступны только внутри пакета, с большой извне тоже.
Типы
nil
- отсутствие значения.bool
- по-умолчанию false.- Стандартные битовые операции.
int
- по-умолчанию 0.int
.int8
—int64
.uint
.uint8
—uint64
.- Стандартные числовые операции, а также
++, {op}=
. - Алиасы -
byte
дляint8
,rune
дляint32
,int
дляint32/int64
. - Поддерживаются битовые операции.
float
- по-умолчанию 0.0 (естьfloat32
иfloat64
).complex
- существуютcomplex128
иcomplex64
(объявляются как в математике5i + 1
).массив
- всегда фиксированной длины.- ПЕРЕДАЮТСЯ ПО ЗНАЧЕНИЮ.
- Вместимость и длина совпадают (
cap
иlen
). - Можно объявить несколькими способами.
var list [5]int
list2 := [...]int {1, 2, 3, 4, 5} // Рассчитает размер автоматически
var list3 = [5]int{1} // 1,0,0,0,0
- срезы - не имеют фиксированной длины, но имеют вместимость.
- ПЕРЕДАЮТСЯ ПО ССЫЛКЕ.
- Можно сделать из массива (по ссылке) как в Питоне
arr[:]
arr[1:3]
и тд. - Вместимость и длина (
cap
иlen
) могут не совпадать. - Суть емкости (вместимости) в том, что если мы выйдем за её пределы, то массив внутри будет пересоздан.
- Функции.
len
,cap
,make(type, len, cap)
,copy(to, from)
,append(slice, val...)
.- Развернуть в аргументы можно с помощью
...
.
- Можно объявить несколькими способами.
var slice []int = []int{1} // [1]
slice1 := make([]int, 5, 15) // [0,0,0,0,0]
string
-"string"
и ‵string‵ (как ‘ в PHP), изначально в UTF-8.- конкатенация
+
. - Можно брать срезы в UTF-8 или через приведение к
[]rune
.
- конкатенация
map
.- ПЕРЕДАЮТСЯ ПО ССЫЛКЕ.
- Можно создать через
make
.
var one map[string]int = map[string]int{"a": 1, "w": 2}
two := make(map[int]bool, 16)
three := map[string]string
- Работа с ключами аналогична массиву, удалить с помощью функции
delete
. - Если обратиться к несуществующему ключу, то вернется значение по-умолчанию.
- Проверка на существование.
value, exist := someMap["someKey"]
// exist булев тип, которые говорит об установке значения
pointer
- Указатели, это переменные, которые хранят ссылки на другие переменные.
- Создать ссылку можно с помощью
&
. - Сам указатель имеет тип
*{type}
, где {type} - тип на который он ссылается. - Получить значение можно с помощью
*
.
one := 1
var ref *int = &one
fmt.Println(one) // 1
fmt.Println(ref) // address of one
fmt.Println(*ref) // 1
Управляющие конструкции
if-else if-else
- стандартная конструкция
if false {
// do something
} else if {
// do something
} else {
}
- Можно выполнить предварительно команду
if a := 1; a > 1 {}
. - switch-case.
- boolcall.
switch {
case false:
// do some
case 2 > 1:
// do some
default:
// do some
}
- casexpr: есть несколько вариантов (
fallthrough
- противоположный break).
switch a := "hello"; a {
case "hel":
// do some
case "hello":
// do some
default:
// do some
}
b := "hello";
switch b {
case "hel":
fallthrough
case "hello":
// do some
default:
// do some
}
- type.
var c interface{}
switch c.(type) {
case string:
// do some
case int:
// do some
}
for
- единственный цикл (работаетbreak
,continue
).- без аргументов - бесконечный.
for {
if a < 1 {
break
}
a--
continue
println(1)
}
- три аргумента (1 обязательный).
for i := 0; i < 10; i++ {
if i < 1 {
break
}
continue
println(1)
}
- обход коллекций.
a := [5]int{1, 2, 3, 4, 5}
for index := range a {
// a[index]
}
var m = map[string]int{"a": 1, "b": 2}
for k, v := range m {
println(k,v)
}
- обход без использования индексов.
for range x {
fmt.Println("Hello")
}
Функции
- Объявляются
func name(arg type, orArgs type...) returnType {}
. - Возвращает через
return
. - Есть замыкания.
- Можно присвоить в переменную.
- Можно вернуть или передать как аргумент, тип:
func (arg type) returnType
. - Можно вызвать на месте.
func () {
println("A'm executed")
}()
- Можно вернуть несколько значений.
var f1 = func() (int, int) {
return 1, 2
}
var a1, b1 = f1()
println(a1)
println(b1)
Функции пакета, начинающиеся с маленькой буквы доступны только внутри пакета, с большой извне тоже.
Области видимости
- Переменные внутри блока (даже просто в
{}
) доступны по значению, то есть при переопределении внешняя не меняется. - Переменные доступны по ссылке только явно или для срезов массивов, мап.
Инструкция defer
- Откладывает выполнение функции в конец, как в очередь (то есть выполнения в обратном порядке).
Отлов ошибок
- try/catch НЕТ.
- panic(str) - сообщает об ошибке и всплывает.
- recover() - возвращает ошибку.
- Конструкция используется совместно с defer.
defer func() {
if err := recover(); err != nil {
println(err)
println("No panic, please")
}
}()
panic("Something wrong!!!")
Алиасы типов
type I = int64
Теперь можно указывать I как псевдоним для int64.
Пользовательские типы подобны алиасам типов
type RichInt int
.- Таким типам можно добавлять методов так же как и структурам.
type richint int
func (r *richint) toString() string {
return string(*r)
}
var i4 richint = 1
i4.toString()
Структуры
- Структуры объявляются как пользовательский тип от
struct
, внутри блока находятся объявления свойств.
type Person struct {
name string
}
- Методы добавляются отдельно с указанием типа.
func (this *Person) sayHi() {
println("Hi, I am " + this.name)
}
- Наследование решено за счет встраивания, необходимо добавить безымянное свойство структуре.
type Bob struct {
Person
age int
}
- Ему доступны все свойства родителя, можно передавать в функции как при наследовании.
- К методам и свойствам можно обратиться 2мя способами.
type Bob struct {
Person
age int
}
bb := Bob{age: 45}
bb.name = "Bob"
bb.Person.sayHi()
bb.sayHi()
- Можно переопределить метод, но иметь к нему доступ через
.parent.method()
.
Интерфейс
Объявляется как
type InterfaceName interface {
method(args int...) string
}
- Явно указать наследование нельзя, используется утиная типизация.
- Есть если у структуры есть метод, то он является подтипом интерфейса.
- Можно встроить интерфейс в интерфейс.
Горутины
- С помощью ключевого слова go можно выполнить функцию в отдельной горутине (main тоже выполняется в отдельной).
a := [5]int{1, 2, 3, 4, 5}
var f = func(i int) {
fmt.Println(i)
}
for i := range a {
go f(i)
}
С помощью пакета sync.WaitGroup
можно ожидать окончания выполнения горутин
Каналы - это специализированный тип для передачи данных между горутинами
- Создается через make(chan typeOf channel, buffer), где буфер - это количество сообщений.
- Каналы - ССЫЛКИ.
- Закрывается через функцию close.
- Посылаем в канал chanvar <- msg.
- Получаем из канала <-chanvar.
- Когда Go доходит до отправки в канал, то он блокирует текущую горутину, ждет пока там будет буфер(место).
- Поэтому лучше объявить буфер, чтобы не было дедлоков.
package main
import (
"fmt"
"time"
"strconv"
)
func printMsg(name string, ch chan string) {
for {
fmt.Println(name + <-ch)
}
}
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
ch := make(chan string)
for _, name := range [5]int{1, 2, 3, 4, 5} {
go printMsg(strconv.Itoa(name) + " : ", ch)
}
for _, msg := range [10]string{"A","B","C","D","E","F","J","K","L","M"} {
ch <- msg
}
time.Sleep(1000 * 1000)
close(ch)
}
- Можно указать тип на только получение из канала или только запись.
func receive(c <-chan string) {}
func send(c chan <- string) {}
- select работает подобно switch, но в каждом кейсе указывается канал, откуда получено сообщение.
select {
case msg := <- ch1:
// do some
case msg := <- ch2:
// do some
default:
// do some
}