Skip to content

Go Шпаргалка по языку программирования

Go (также известный как Golang) — это статически типизированный компилируемый язык, разработанный Робертом Гризмером, Робом Пайком и Кеном Томпсоном в Google. Синтаксис Go схож с C, но обладает такими особенностями, как безопасность памяти, GC (сборка мусора), структурная типизация и конкурентность в стиле CSP.

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

Переменные

Объявление переменных

var msg string
msg = "Hello"

Краткая форма

msg := "Hello"

Константы

const Phi = 1.618

Константы могут быть символами, строками, логическими или числовыми значениями.

Базовые типы

Строки (Strings)

str := "Hello"
str := `Многострочная
строка`

Тип строк — string.

Числа

Типичные типы

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (псевдоним для uint8)

Другие типы

var u uint = 7        // uint (беззнаковое)
var p float32 = 22.7  // 32-битный float

Указатели

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

Указатели указывают на адрес переменной в памяти. В Go реализована полноценная сборка мусора.

Массивы (Arrays)

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

Массивы имеют фиксированный размер.

Срезы (Slices)

slice := []int{2, 3, 4}
slice := []byte("Hello")

В отличие от массивов, срезы имеют динамический размер.

Управление потоком

Условные операторы

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

Инструкция внутри if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

Оператор if может выполнять простую инструкцию перед проверкой условия.

Switch

switch day {
  case "sunday":
    // в Go нет автоматического перехода (fall through)!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

Функции

Лямбда-функции (анонимные)

myfunc := func() bool {
  return x > 10000
}

Функции в Go являются объектами первого класса.

Несколько возвращаемых значений

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Именованные возвращаемые значения

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

Если возвращаемые значения названы при объявлении, пустой оператор return вернет переменные с этими именами.

Пакеты (Packages)

Импорт

import "fmt"
import "math/rand"
import (
  "fmt"        // дает доступ к fmt.Println
  "math/rand"  // дает доступ к rand.Intn
)

Оба способа идентичны.

Псевдонимы (Aliases)

import r "math/rand"
 
r.Intn()

Экспортируемые имена

func Hello () {
  ···
}

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

Пакеты

package hello

Каждый файл пакета должен начинаться с инструкции package.

Конкурентность

Горутины (Goroutines)

func main() {
  // Канал (channel)
  ch := make(chan string)

  // Запуск конкурентных функций
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Чтение 3 результатов
  // (Так как горутины работают конкурентно,
  // порядок не гарантирован!)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

Каналы — это безопасные для конкурентного использования объекты связи между горутинами.

Буферизованные каналы

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

Буферизованные каналы ограничивают количество сообщений, которые они могут хранить.

Закрытие каналов

Закрывает канал

ch <- 1
ch <- 2
ch <- 3
close(ch)

Итерация по каналу до его закрытия

for i := range ch {
  ···
}

Канал закрыт, если ok == false

v, ok := <- ch

Defer & Panic

Defer

func main() {
  defer fmt.Println("Готово")
  fmt.Println("Работаем...")
}

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

Defer с лямбда-функциями

func main() {
  defer func() {
    fmt.Println("Готово")
  }()
  fmt.Println("Работаем...")
}

Анонимные функции лучше подходят для блоков defer.

Структуры (Structs)

Определение

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

Литералы

v := Vertex{X: 1, Y: 2}
// Имена полей можно опустить
v := Vertex{1, 2}
// Y подразумевается
v := Vertex{X: 1}

Вы также можете указывать имена полей.

Указатели на структуры

v := &Vertex{1, 2}
v.X = 2

Если v является указателем, запись v.X эквивалентна (*v).X.

Методы

Получатели (Receivers)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v := Vertex{1, 2}
v.Abs()

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

Указатели-получатели

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// `v` обновится