Skip to content

21.1 Основы Golang

Философия Go

Какие проблемы решает

  • Медленная сборка программ
  • Неконтролируемые зависимости
  • Использования разными программистами разных подмножеств языка
  • Затруднения с пониманием программ
  • Сложность разработки инструментария

Специфика

  • Мало сахара (один способ решить задачу)
  • Быстрая компиляция
  • Нет эксепшенов
  • Очень ограниченное число операций
  • Поддержка указателей без арифметики над ними

Переменные

var v1 int

fmt.Println(v1)

var v2 int = 100

v3 := 5

var v5, v6 = 1,2

v5,v6 = 3,4

var (
  v01 = 1
  v02 = "string"
)

# Игнорирование переменных
_ = v01

Константы

const c1 int = 42

Указатели

Переменные это блок памяти в которой хранятся наши данные Значением указателя - является адрес этого блока памяти

1
2
3
x := 1
ptr := &x
*ptr = 5

Синонимы числовых типов

type rune = int32 // Представляет собой unicode символ
type byte = uint8

Числа с плавающей точкой

float32 // точность 6 знаков после запятой
float64 // точность 15 знаков после запятой

Строки

Строка это неизменяемая последовательность байтов

var myString string

word := "my string"

var b byte = 'c' // равно 99 - восьмибитное представление
var r rune = '你' // равно 20320 - Полноценное utf8 представление

str = "some text."
fmt.Println(len(str)) // 9 - Количество БАЙТ! в строке
fmt.Println(str[1]) // 111

Составные типы

  • Array
  • Slice
  • Map
  • Struct

Массивы

Последовательность фиксированной длины

1
2
3
4
5
6
7
var x1 [5]int

var arr [3]int = [3]int{1,2,3}
var arr2 = [3]int{1,2,3}
arr3 := [3]int{1,2,3}
arr3 = [2]int{1,2} // Ошибка - нельзя присвоить 2 значением
arr5 := [...]int32{1,2,3,4,5}

Slice

Последовательность переменной длины Под капотом у срезов лежат массивы Емкость среза это предел до конца массивы

var list []string

list = []int64{1,2,3,4,5}
l = len(list) // 5
c = cap(list) // 5

list = make([]int64, 0, 5])
l = len(list) // 0
c = cap(list) // 5

list = make([]int64, 5, 5]) // [0,0,0,0,0]
l = len(list) // 5
c = cap(list) // 5

list = []int64{1,2,3,4}
// Функция append len увеличивается на 1,
// если больше cap то создается новый массив и значение переносится туда
list = append(list, 5)
l = len(list) // 5
c = cap(list) // 8

Map

var m1 map[int32]bool

m3 := make(map[int]int)

ages := map[string]int {
  "Mike": 30,
  "Jon": 24,
  // ...
}

age := ages["Mike"] // 30
ages["Bob"] = 31
// Вывод значения которого не существует
fmt.Println(ages["Max"]) // 0
ages["Max"]++ // ["Max": 1]

Struct

Агрегированный тип данных

type Point struct {
  X int
  Y int
  Z int
  T []int64
}

p = Point{5, 15}

fmt.Println(p.X)

p.X = 55

Функции

func addPrefix(origin string) string {
  return "prefix_" + origin
}

func addPrefixWithLen(origin string) (res string, length int) {
  // На этапе начала функции переменные уже получат дефолтные значения
  res = "prefix_" + origin
  length = len(res)
  return res, length
}

Анонимные функции

1
2
3
f := func() {...}

s := strings.Map(func(r rune) rune {return r + 1}, "TEXT")

Отложенный вызов функции DEFER

Аргументы вычисляются на момент объявления defer, но фактический вызов будет отложен Defer - если несколько то выполняются в обратном порядке

Циклы и условные операторы

if a == 5 {
  // pass
}

switch a {
case 1:
  // pass
default:
  // pass
}

switch {
case a > 1 || b < 10:
  // pass
default:
  // pass
}

Циклы

for {
  // бесконечный цикл
}

for a == 5 {
  // pass
}

for i := 0; i < 10; i++ {
  // pass
}

sl := []int64{1,2,3}

for key, value := range sl {
  fmt.Printf("key: %v, val: %v \n", key, value)
}

word := "привет"

for i := 1; i < len(word); i++ {
  fmt.Printf("%T", word[i]) // Выводит байты
}

for key, value := range word {
  fmt.Println(value) // Выводит rune
}

Структуры

Поля структуры

// new - встроенная в язык функция которая возвращает адрес на выделенную память
i := new(int64)

type Avatar struct {
  URL string
  Size int64
}

type Client struct {
  ID int64
  Name string
  Age int
  IMG *Avatar
}

func updateAvatar(client Client){
  client.IMG.URL = "updated_url"
}

client := Client{} // Будут присвоены все дефолтные поля
updateAvatar(client) // Не правильно, передача по значению!

////////
func updateAvatar(client *Client){
  client.IMG.URL = "updated_url"
}

client := Client{}
// client.IMG = new(Avatar)
client.IMG = &Avatar{}
updateAvatar(&client) // Правильно

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

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

finc (p Point) myMethod (param int) string {
  // pass
}

func (c Client) HasAvatar() bool {
  if c.IMG != nil && c.IMG.URL != "" {
    return true
  }
  return false
}

func (c Client) UpdateAvatar() {
  c.IMG.URL = "new_url"
}


func main() {
  client := Client{
    ID: 7,
    Name: "Bob",
    Age: 20,
    IMG: &Avatar{
      URL: "test",
    },
  }
  fmt.Printf("%#v", client)
  fmt.Println(client.HasAvatar())
}