Go (часто также Golang) — компилируемый многопоточный язык программирования, разработанный внутри компании Google
Язык Go разрабатывался как язык программирования для создания высокоэффективных программ, работающих на современных распределённых системах и многоядерных процессорах. Он может рассматриваться как попытка создать замену языкам C/C++. По словам Роба Пайка, "Go был разработан для решения реальных проблем, возникающих при разработке программного обеспечения в Google". В качестве основных таких проблем он называет:
- Медленную сборку программ
- Неконтролируемые зависимости
- Использование разными программистами разных подмножеств языка
- Затруднения с пониманием программ, вызванные неудобочитаемостью кода, плохим документированием
- Дублирование разработок
- Высокую стоимость обновлений
- Несинхронные обновления при дублировании кода
- Сложность разработки инструментария
Основными требованиями к языку стали:
- Ортогональность. Язык должен предоставлять небольшое число средств, не повторяющих функциональность друг друга
- Простая и регулярная грамматика. Минимум ключевых слов, простая, легко разбираемая грамматическая структура, легко читаемый код
- Простая работа с типами. Типизация должна обеспечивать безопасность, но не превращаться в бюрократию, лишь увеличивающую код. Отказ от иерархии типов, но с сохранением объектно-ориентированных возможностей
- Отсутствие неявных преобразований
- Сборка мусора
- Встроенные средства распараллеливания, простые и эффективные
- Поддержка строк, ассоциативных массивов и коммуникационных каналов
- Чёткое разделение интерфейса и реализации
- Эффективная система пакетов с явным указанием зависимостей, обеспечивающая быструю сборку
Go создавался в расчёте на то, что программы на нём будут транслироваться в объектный код целевой аппаратной и программной платформы и в дальнейшем исполняться непосредственно, не требуя виртуальной машины, поэтому одним из критериев выбора архитектурных решений была возможность обеспечить быструю компиляцию в эффективный объектный код и отсутствие чрезмерных требований к динамической поддержке.
В результате получился язык, "который не стал прорывом, но тем не менее явился отличным инструментом для разработки крупных программных проектов".
- Go — язык со строгой статической типизацией. Доступен автоматический вывод типов, для пользовательских типов — "утиная типизация"
- Полноценная поддержка указателей, но без возможности применять к ним арифметические операции, в отличие от C/C++
- Строковый тип со встроенной поддержкой Unicode
- Использование динамических массивов, хеш-таблиц, срезов (слайсов), вариант цикла для обхода коллекции
- Средства функционального программирования: неименованные функции, замыкания, передача функций в параметрах и возврат функциональных значений
- Автоматическое управление памятью со сборщиком мусора
- Средства объектно-ориентированного программирования, но без поддержки наследования реализации (наследуются только интерфейсы). По большому счёту, Go является процедурным языком с поддержкой интерфейсов
- Средства параллельного программирования: встроенные в язык потоки (go routines), взаимодействие потоков через каналы и другие средства организации многопоточных программ
- Достаточно лаконичный и простой синтаксис, основанный на Си, но существенно доработанный, с большим количеством синтаксического сахара
- Целые числа
int
,int8
,int16
,int32
,int64
иrune
(то же самое, чтоint32
)uint
,uintptr
,uint8
,uint16
,uint32
,uint64
иbyte
(то же самое, чтоuint8
)
- Числа с плавающей точкой
float32
иfloat64
complex64
иcomplex128
- Строки
string
- Логические значения
bool
# Ubuntu
sudo add-apt-repository ppa:longsleep/golang-backports
sudo apt-get update
sudo apt-get install golang-go
# macOS
brew install golang
Hello World
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Пакеты
package main
/* Импорт */
import (
"fmt" // Стандартный пакет для форматированного вывода
"database/sql" // Импорт вложенного пакета
w "os" // Импорт с псевдонимом
. "math" // Импорт без квалификации при использовании
_ "gopkg.in/goracle.v2" // Пакет не имеет явных обращений в коде
)
func main() {
for _, arg := range w.Args { // Обращение к массиву Args, объявленному в пакете "os", через псевдоним
fmt.Println(arg) // Обращение к функции Println(), объявленной в пакете "fmt", с именем пакета
}
db *sql.DB = sql.Open(driver, dataSource) // Имена из вложенного пакета квалифицируются только именем самого пакета (sql)
x := Sin(1.0) // вызов math.Sin() - квалификация именем пакета math не нужна,
// так как он импортирован без имени
// Обращений к пакету "goracle.v2" в коде нет, но он будет импортирован.
}
Механизм отложенного вызова
// Функция, копирующая файл
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName) // Открытие файла-источника
if err != nil { // Проверка
return // Если неудача, возврат с ошибкой
}
// Если пришли сюда, то файл-источник был успешно открыт
defer src.Close() // Отложенный вызов: src.Close() будет вызван по завершении CopyFile
dst, err := os.Create(dstName) // Открытие файла-приёмника
if err != nil { // Проверка и возврат при ошибке
return
}
defer dst.Close() // Отложенный вызов: dst.Close() будет вызван по завершении CopyFile
return io.Copy(dst, src) // Копирование данных и возврат из функции
// После всех операций будут вызваны: сначала dst.Close(), затем src.Close()
}
Обработка ошибок
func ReadFile(srcName string)(result string, err error) {
file, err := os.Open("file.txt")
if err != nil {
// Генерация новой ошибки с уточняющим текстом
return nil, fmt.Errorf("Ошибка при чтении файла %s: %g\n", srcName, err)
}
... // Дальнейшее исполнение функции, если ошибки не было
return result, nil // Возврат результата и пустой ошибки, если выполнение успешно
}
Goroutines
func main() {
var wg sync.WaitGroup // Создание waitgroup. Исходное значение счётчика - 0
logger := log.New(os.Stdout, "", 0) // log.Logger - потоково-безопасный тип для вывода
for _, arg := range os.Args { // Цикл по всем аргументам командной строки
wg.Add(1) // Увеличение счётчика waitgroup на единицу
// Запуск go-процедуры для обработки параметра arg
go func(word string) {
// Отложенное уменьшение счётчика waitgroup на единицу.
// Произойдёт по завершении функции.
defer wg.Done()
logger.Println(prepareWord(word)) // Выполнение обработки и вывод результата
}(arg)
}
wg.Wait() // Ожидание, пока счётчик в waitgroup wg не станет равным нулю.
}
Каналы
in := make(chan string, 0) // Создание небуферизованного канала in
out := make(chan int, 10) // Создание буферизованного канала out
...
in <- arg // запись значения в канал in
...
r1 := <- out // чтение из канала out
...
r2, ok := <- out // чтение с проверкой закрытия канала
if ok { // если ok == true - канал открыт
...
} else { // если канал закрыт, делаем что-то ещё
...
}
Интроспекция — показать все методы объекта
fooType := reflect.TypeOf(someObj)
for i := 0; i < fooType.NumMethod(); i++ {
method := fooType.Method(i)
fmt.Println(method.Name)
}