go.md

Личный сайт Go-разработчика из Казани

Go - это язык общего назначения, целью которого является удобство, простота, конкурентность. Это не тренд в компьютерных науках, а новейший и быстрый способ решать насущные проблемы.

Концепции Go схожи с другими императивными статически типизированными языками. Быстро компилируется и быстро исполняется, имеет лёгкие в понимании конструкции для создания масштабируемых и многопоточных программ.

Может похвастаться отличной стандартной библиотекой и большим комьюнити, полным энтузиастов.

1// Однострочный комментарий 2/* Многострочный 3 комментарий */ 4 5// Ключевое слово package присутствует в начале каждого файла. 6// main это специальное имя, обозначающее исполняемый файл, нежели библиотеку. 7package main 8 9// Import предназначен для указания зависимостей этого файла. 10import ( 11 "fmt" // Пакет в стандартной библиотеке Go 12 "io/ioutil" // Реализация функций ввод/вывода. 13 "net/http" // Да, это веб-сервер! 14 "strconv" // Конвертирование типов в строки и обратно 15 m "math" // Импортировать math под локальным именем m. 16) 17 18// Объявление функции. Main это специальная функция, служащая точкой входа для 19// исполняемой программы. Нравится вам или нет, но Go использует фигурные 20// скобки. 21func main() { 22 // Println выводит строку в stdout. 23 // Данная функция находится в пакете fmt. 24 fmt.Println("Hello world!") 25 26 // Вызов другой функции из текущего пакета. 27 beyondHello() 28} 29 30// Функции содержат входные параметры в круглых скобках. 31// Пустые скобки все равно обязательны, даже если параметров нет. 32func beyondHello() { 33 var x int // Переменные должны быть объявлены до их использования. 34 x = 3 // Присвоение значения переменной. 35 // Краткое определение := позволяет объявить переменную с автоматической 36 // подстановкой типа из значения. 37 y := 4 38 sum, prod := learnMultiple(x, y) // Функция возвращает два значения. 39 fmt.Println("sum:", sum, "prod:", prod) // Простой вывод. 40 learnTypes() // < y minutes, learn more! 41} 42 43// Функция, имеющая входные параметры и возвращающая несколько значений. 44func learnMultiple(x, y int) (sum, prod int) { 45 return x + y, x * y // Возврат двух значений. 46} 47 48// Некоторые встроенные типы и литералы. 49func learnTypes() { 50 // Краткое определение переменной говорит само за себя. 51 s := "Learn Go!" // Тип string. 52 53 s2 := `"Чистый" строковой литерал 54может содержать переносы строк` // Тоже тип данных string 55 56 // Символ не из ASCII. Исходный код Go в кодировке UTF-8. 57 g := 'Σ' // тип rune, это алиас для типа int32, содержит символ юникода. 58 59 f := 3.14159 // float64, 64-х битное число с плавающей точкой (IEEE-754). 60 c := 3 + 4i // complex128, внутри себя содержит два float64. 61 62 // Синтаксис var с инициализациями. 63 var u uint = 7 // Беззнаковое, но размер зависит от реализации, как и у int. 64 var pi float32 = 22. / 7 65 66 // Синтаксис приведения типа с кратким определением 67 n := byte('\n') // byte – это алиас для uint8. 68 69 // Массивы имеют фиксированный размер на момент компиляции. 70 var a4 [4]int // массив из 4-х int, инициализирован нулями. 71 a3 := [...]int{3, 1, 5} // массив из 3-х int, ручная инициализация. 72 73 // Слайсы (slices) имеют динамическую длину. И массивы, и слайсы имеют свои 74 // преимущества, но слайсы используются гораздо чаще. 75 s3 := []int{4, 5, 9} // Сравните с a3, тут нет троеточия. 76 s4 := make([]int, 4) // Выделение памяти для слайса из 4-х int (нули). 77 var d2 [][]float64 // Только объявление, память не выделяется. 78 bs := []byte("a slice") // Синтаксис приведения типов. 79 80 p, q := learnMemory() // Объявление p и q как указателей на int. 81 fmt.Println(*p, *q) // * извлекает указатель. Печатает два int-а. 82 83 // Map, также как и словарь или хеш из некоторых других языков, является 84 // ассоциативным массивом с динамически изменяемым размером. 85 m := map[string]int{"three": 3, "four": 4} 86 m["one"] = 1 87 88 delete(m, "three") // Встроенная функция, удаляет элемент из map-а. 89 90 // Неиспользуемые переменные в Go являются ошибкой. 91 // Нижнее подчёркивание позволяет игнорировать такие переменные. 92 _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs 93 // Вывод считается использованием переменной. 94 fmt.Println(s, c, a4, s3, d2, m) 95 96 learnFlowControl() // Идем дальше. 97} 98 99// У Go есть полноценный сборщик мусора. В нем есть указатели, но нет арифметики 100// указателей. Вы можете допустить ошибку с указателем на nil, но не с 101// инкрементацией указателя. 102func learnMemory() (p, q *int) { 103 // Именованные возвращаемые значения p и q являются указателями на int. 104 p = new(int) // Встроенная функция new выделяет память. 105 // Выделенный int проинициализирован нулём, p больше не содержит nil. 106 s := make([]int, 20) // Выделение единого блока памяти под 20 int-ов. 107 s[3] = 7 // Присвоить значение одному из них. 108 r := -2 // Определить ещё одну локальную переменную. 109 return &s[3], &r // Амперсанд(&) обозначает получение адреса переменной. 110} 111 112func expensiveComputation() float64 { 113 return m.Exp(10) 114} 115 116func learnFlowControl() { 117 // If-ы всегда требуют наличие фигурных скобок, но не круглых. 118 if true { 119 fmt.Println("told ya") 120 } 121 // Форматирование кода стандартизировано утилитой "go fmt". 122 if false { 123 // Будущего нет. 124 } else { 125 // Жизнь прекрасна. 126 } 127 // Используйте switch вместо нескольких if-else. 128 x := 42.0 129 switch x { 130 case 0: 131 case 1: 132 case 42: 133 // Case-ы в Go не "проваливаются" (неявный break). 134 case 43: 135 // Не выполнится. 136 } 137 // For, как и if не требует круглых скобок 138 // Переменные, объявленные в for и if являются локальными. 139 for x := 0; x < 3; x++ { // ++ – это операция. 140 fmt.Println("итерация", x) 141 } 142 // Здесь x == 42. 143 144 // For – это единственный цикл в Go, но у него есть альтернативные формы. 145 for { // Бесконечный цикл. 146 break // Не такой уж и бесконечный. 147 continue // Не выполнится. 148 } 149 // Как и в for, := в if-е означает объявление и присвоение значения y, 150 // проверка y > x происходит после. 151 if y := expensiveComputation(); y > x { 152 x = y 153 } 154 // Функции являются замыканиями. 155 xBig := func() bool { 156 return x > 10000 // Ссылается на x, объявленный выше switch. 157 } 158 fmt.Println("xBig:", xBig()) // true (т.к. мы присвоили x = e^10). 159 x = 1.3e3 // Тут х == 1300 160 fmt.Println("xBig:", xBig()) // Теперь false. 161 162 // Метки, куда же без них, их все любят. 163 goto love 164love: 165 166 learnDefer() // Быстрый обзор важного ключевого слова. 167 learnInterfaces() // О! Интерфейсы, идём далее. 168} 169 170func learnDefer() (ok bool) { 171 // Отложенные(deferred) выражения выполняются сразу перед тем, как функция 172 // возвратит значение. 173 defer fmt.Println("deferred statements execute in reverse (LIFO) order.") 174 defer fmt.Println("\nThis line is being printed first because") 175 // defer широко используется для закрытия файлов, чтобы закрывающая файл 176 // функция находилась близко к открывающей. 177 return true 178} 179 180// Объявление Stringer как интерфейса с одним методом, String. 181type Stringer interface { 182 String() string 183} 184 185// Объявление pair как структуры с двумя полями x и y типа int. 186type pair struct { 187 x, y int 188} 189 190// Объявление метода для типа pair. Теперь pair реализует интерфейс Stringer. 191func (p pair) String() string { // p в данном случае называют receiver-ом. 192 // Sprintf – ещё одна функция из пакета fmt. 193 // Обращение к полям p через точку. 194 return fmt.Sprintf("(%d, %d)", p.x, p.y) 195} 196 197func learnInterfaces() { 198 // Синтаксис с фигурными скобками это "литерал структуры". Он возвращает 199 // проинициализированную структуру, а оператор := присваивает её p. 200 p := pair{3, 4} 201 fmt.Println(p.String()) // Вызов метода String у переменной p типа pair. 202 var i Stringer // Объявление i как типа с интерфейсом Stringer. 203 i = p // Валидно, т.к. pair реализует Stringer. 204 // Вызов метода String у i типа Stringer. Вывод такой же, что и выше. 205 fmt.Println(i.String()) 206 207 // Функции в пакете fmt сами всегда вызывают метод String у объектов для 208 // получения строкового представления о них. 209 fmt.Println(p) // Вывод такой же, что и выше. Println вызывает метод String. 210 fmt.Println(i) // Вывод такой же, что и выше. 211 212 learnVariadicParams("Учиться", "учиться", "и ещё раз учиться!") 213} 214 215// Функции могут иметь варьируемое количество параметров. 216func learnVariadicParams(myStrings ...interface{}) { 217 // Вывести все параметры с помощью итерации. 218 for _, param := range myStrings { 219 fmt.Println("param:", param) 220 } 221 222 // Передать все варьируемые параметры. 223 fmt.Println("params:", fmt.Sprintln(myStrings...)) 224 225 learnErrorHandling() 226} 227 228func learnErrorHandling() { 229 // Идиома ", ok" служит для обозначения корректного срабатывания чего-либо. 230 m := map[int]string{3: "three", 4: "four"} 231 if x, ok := m[1]; !ok { // ok будет false, потому что 1 нет в map-е. 232 fmt.Println("тут никого нет") 233 } else { 234 fmt.Print(x) // x содержал бы значение, если бы 1 был в map-е. 235 } 236 // Идиома ", err" служит для обозначения была ли ошибка или нет. 237 if _, err := strconv.Atoi("non-int"); err != nil { // _ игнорирует значение 238 // выведет "strconv.ParseInt: parsing "non-int": invalid syntax" 239 fmt.Println(err) 240 } 241 // Мы ещё обратимся к интерфейсам чуть позже, а пока... 242 learnConcurrency() 243} 244 245// c – это тип данных channel (канал), объект для конкурентного взаимодействия. 246func inc(i int, c chan int) { 247 c <- i + 1 // когда channel слева, <- является оператором "отправки". 248} 249 250// Будем использовать функцию inc для конкурентной инкрементации чисел. 251func learnConcurrency() { 252 // Тот же make, что и в случае со slice. Он предназначен для выделения 253 // памяти и инициализации типов slice, map и channel. 254 c := make(chan int) 255 // Старт трех конкурентных goroutine. Числа будут инкрементированы 256 // конкурентно и, может быть параллельно, если машина правильно 257 // сконфигурирована и позволяет это делать. Все они будут отправлены в один 258 // и тот же канал. 259 go inc(0, c) // go начинает новую горутину. 260 go inc(10, c) 261 go inc(-805, c) 262 // Считывание всех трех результатов из канала и вывод на экран. 263 // Нет никакой гарантии в каком порядке они будут выведены. 264 fmt.Println(<-c, <-c, <-c) // канал справа, <- обозначает "получение". 265 266 cs := make(chan string) // другой канал, содержит строки. 267 cc := make(chan chan string) // канал каналов со строками. 268 go func() { c <- 84 }() // пуск новой горутины для отправки значения 269 go func() { cs <- "wordy" }() // ещё раз, теперь для cs 270 // Select тоже что и switch, но работает с каналами. Он случайно выбирает 271 // готовый для взаимодействия канал. 272 select { 273 case i := <-c: // полученное значение можно присвоить переменной 274 fmt.Printf("это %T", i) 275 case <-cs: // либо значение можно игнорировать 276 fmt.Println("это строка") 277 case <-cc: // пустой канал, не готов для коммуникации. 278 fmt.Println("это не выполнится.") 279 } 280 // В этой точке значение будет получено из c или cs. Одна горутина будет 281 // завершена, другая останется заблокированной. 282 283 learnWebProgramming() // Да, Go это может. 284} 285 286// Всего одна функция из пакета http запускает web-сервер. 287func learnWebProgramming() { 288 // У ListenAndServe первый параметр это TCP адрес, который нужно слушать. 289 // Второй параметр это интерфейс типа http.Handler. 290 err := http.ListenAndServe(":8080", pair{}) 291 fmt.Println(err) // не игнорируйте сообщения об ошибках 292} 293 294// Реализация интерфейса http.Handler для pair, только один метод ServeHTTP. 295func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { 296 // Обработка запроса и отправка данных методом из http.ResponseWriter 297 w.Write([]byte("You learned Go in Y minutes!")) 298} 299 300func requestServer() { 301 resp, err := http.Get("http://localhost:8080") 302 fmt.Println(err) 303 defer resp.Body.Close() 304 body, err := ioutil.ReadAll(resp.Body) 305 fmt.Printf("\nWebserver said: `%s`", string(body)) 306}

Что дальше

Основа всех основ в Go это официальный веб сайт. Там можно пройти туториал, поиграться с интерактивной средой Go и почитать объёмную документацию.

Для живого ознакомления рекомендуется почитать исходные коды стандартной библиотеки Go. Отлично задокументированная, она является лучшим источником для чтения и понимания Go, его стиля и идиом. Либо можно, кликнув на имени функции в документации, перейти к ее исходным кодам.