Go Playground
В прошлом уроке мы разобрали весь путь от исходного кода до бинарника — go run, go build, кросс-компиляцию. Всё это требует установленного Go и терминала. Но что если хочется быстро проверить идею, а Go под рукой нет? Или нужно показать коллеге фрагмент кода так, чтобы он мог сразу его запустить?
Для этого существует Go Playground — официальный веб-сервис, где можно писать, запускать и делиться Go-кодом прямо в браузере. Без установки, без настройки, без регистрации.
Что такое Go Playground
Откройте в браузере go.dev/play. Вы увидите текстовый редактор с уже знакомым кодом:
package main
import "fmt"
func main() { fmt.Println("Hello, World!")}Над редактором — три кнопки: Run, Format и Share. Справа — выпадающий список Examples с 15 готовыми шаблонами и селектор версии Go. Под редактором — панель вывода, куда попадает результат.
Всё. Никаких регистраций, логинов, тарифных планов. Открыли — пишете — запускаете.
Run, Format, Share
Run — запуск кода
Нажмите Run (или Shift+Enter) — код отправляется на серверы Google, компилируется, запускается в изолированной песочнице, и результат возвращается в панель вывода. По сути, это тот же go run, только удалённо.
Попробуйте изменить текст:
package main
import "fmt"
func main() { fmt.Println("Привет из Playground!") fmt.Println(2 + 2) fmt.Println("Go" + " " + "рулит")}Нажмите Run — и через секунду увидите:
Привет из Playground!4Go рулитЗнакомо, правда? Всё то же самое, что мы делали в уроке Hello World — только без терминала.
Format — автоформатирование
Нажмите Format (или Ctrl+Enter) — и код автоматически отформатируется. Но Format в Playground делает больше, чем просто расставляет пробелы. Он работает как goimports: добавляет недостающие импорты и убирает лишние. Напишите:
package main
func main() { fmt.Println(math.Sqrt(16))}Нажмите Format — и Playground сам добавит import "fmt" и import "math". Именно так работал goimports в уроке про структуру программы — только теперь прямо в браузере.
Share — делимся кодом
Нажмите Share — и Playground сгенерирует постоянную ссылку вида go.dev/play/p/AbCdEf12345. Эту ссылку можно отправить кому угодно: коллеге, в чат, на форум. Открыв её, человек увидит ваш код и сможет сразу его запустить.
Ссылки не удаляются. Сниппеты, созданные больше десяти лет назад, до сих пор работают. Playground хранит код по хешу содержимого — если два человека напишут одинаковый код, они получат одну и ту же ссылку.
:::tip Лайфхак Максимальный размер сниппета — 64 КБ. Для коротких примеров этого более чем достаточно, но целый проект туда не поместится. :::
Что можно делать в Playground
Импортировать сторонние пакеты
Playground — это не только стандартная библиотека. Можно использовать любой публичный Go-модуль:
package main
import ( "fmt" "golang.org/x/text/language")
func main() { tag, _ := language.Parse("ru") fmt.Println("Язык:", tag)}Зависимости подтягиваются автоматически через proxy.golang.org — тот же прокси, который go get использует локально. Не нужен ни go.mod, ни go get — Playground всё сделает сам.
:::caution Не все пакеты работают Пакеты, которым нужен CGO (C-код), доступ к сети или файловой системе хоста — не заработают. Но большинство популярных библиотек для обработки данных, форматирования, валидации — работают отлично. :::
Несколько файлов
Playground поддерживает многофайловые проекты через формат txtar. Файлы разделяются маркерами -- имя_файла.go --:
-- go.mod --module examplego 1.22
-- main.go --package main
import ( "fmt" "example/greet")
func main() { fmt.Println(greet.Hello("Мир"))}
-- greet/greet.go --package greet
import "fmt"
func Hello(name string) string { return fmt.Sprintf("Привет, %s!", name)}Playground распакует эту структуру, создаст виртуальные директории и скомпилирует всё как полноценный проект. Максимум — 20 файлов в одном сниппете.
Запуск тестов
Если в коде есть тестовые функции и нет func main(), Playground автоматически запустит go test:
package main
import "testing"
func Reverse(s string) string { runes := []rune(s) for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { runes[i], runes[j] = runes[j], runes[i] } return string(runes)}
func TestReverse(t *testing.T) { got := Reverse("Hello") if got != "olleH" { t.Errorf("Reverse(\"Hello\") = %q, want \"olleH\"", got) }}Нажмите Run — и увидите PASS. Удобно для проверки алгоритмов и демонстрации тестов без локального окружения.
:::tip Бенчмарки не поддерживаются
Playground работает в песочнице с ограниченными ресурсами, поэтому бенчмарки (testing.B) не дадут осмысленных результатов и официально не поддерживаются.
:::
Шаблоны и выбор версии Go
В выпадающем списке Examples — 15 готовых программ: от Hello World до параллельного вычисления числа Пи, HTTP-сервера и работы с дженериками. Полезно для изучения — можно открыть шаблон, поменять пару строк и посмотреть, что изменится.
Селектор версии позволяет переключаться между стабильными релизами Go и веткой разработки. Хотите попробовать фичу из ещё не вышедшей версии? Выберите dev-ветку (gotip).
Ограничения: что Playground делать не умеет
Playground запускает код в изолированной песочнице (sandbox) — ограниченной среде, которая защищает серверы Google от вредоносного кода. Из-за этого есть ряд ограничений.
Жёсткие лимиты
| Ограничение | Значение |
|---|---|
| Время выполнения | 5 секунд |
| Память | 100 МБ |
| Размер сниппета | 64 КБ |
| Файлов в проекте | 20 |
| CGO | Отключён |
| Платформа | linux/amd64 |
Нет сети
Playground не может обращаться к внешним серверам. HTTP-запросы, подключения к базам данных, скачивание файлов — всё это заблокировано. Попытка сделать http.Get("https://example.com") завершится ошибкой.
Но есть нюанс: localhost работает. Можно поднять HTTP-сервер и подключиться к нему из той же программы — в списке шаблонов есть готовый пример “HTTP Server”.
Нет настоящей файловой системы
Файловая система — виртуальная, существует только в памяти. Можно создавать и читать файлы в /tmp в рамках одного запуска, но после завершения программы всё исчезает.
Нет аргументов командной строки
Помните os.Args из урока про структуру программы? В Playground os.Args содержит только один элемент — путь к бинарнику. Передать свои аргументы нельзя.
Фиксированное время
Это самый удивительный нюанс. Попробуйте:
package main
import ( "fmt" "time")
func main() { fmt.Println(time.Now())}Результат:
2009-11-10 23:00:00 +0000 UTCPlayground всегда возвращает одну и ту же дату: 10 ноября 2009 года, 23:00 UTC. Это не баг — это намеренное решение. Именно в этот день Go был представлен публике.
Зачем? Ради детерминизма. Одинаковый код всегда даёт одинаковый результат — и Playground может кэшировать ответы. Если тысяча человек запустит один и тот же Hello World, сервер скомпилирует его один раз, а остальным отдаст результат из кэша. Это экономит огромное количество ресурсов.
time.Sleep при этом работает — но не по-настоящему. Когда все горутины заблокированы, планировщик мгновенно перематывает внутренние часы к следующему таймеру. Программа “думает”, что прошло 2 секунды, а на самом деле прошли миллисекунды. В браузере вывод воспроизводится с правильными задержками — вы видите паузу, хотя выполнение давно закончилось.
:::tip Для опытных: как устроен “фейковый сон”
Playground вставляет в вывод специальные заголовки с метками времени. JavaScript-клиент на странице разбирает эти метки и воспроизводит текст с нужными задержками. Поэтому time.Sleep(2 * time.Second) выглядит как двухсекундная пауза в браузере, хотя сервер всё выполнил за доли секунды.
:::
Когда использовать Playground
Stack Overflow и GitHub Issues
Стандартный способ показать проблему в Go-сообществе — ссылка на Playground. Шаблон баг-репорта в golang/go прямо говорит: “A link on play.golang.org is best”. Минимальный воспроизводимый пример в одном клике — это экономит время всем.
pkg.go.dev — документация с кнопкой Run
На страницах документации Go-пакетов (pkg.go.dev) рядом с каждым примером (Example) есть кнопка Run. Нажмите — и код выполнится через Playground прямо на странице. Не нужно ничего копировать и вставлять — потыкали, поняли, как работает API.
Быстрые эксперименты
“А что будет, если…” — открыл Playground, написал три строки, нажал Run. Быстрее, чем открывать VS Code, создавать файл и запускать go run .. Особенно если вы на чужом компьютере или на планшете.
Playground vs VS Code
| Go Playground | VS Code + Go | |
|---|---|---|
| Установка | Не нужна | Go + VS Code + расширение |
| Автодополнение | Нет | gopls |
| Отладка | Нет | Delve |
| Сеть и файлы | Песочница | Полный доступ |
| Время выполнения | 5 секунд | Без ограничений |
| Поделиться кодом | Одна кнопка | Копировать вручную |
| Для чего | Эксперименты, примеры, обучение | Реальная разработка |
Playground — не замена редактору. Это дополнение: быстрый блокнот для экспериментов и универсальный способ поделиться кодом.
Альтернативы
goplay.tools
Сторонний клиент для Playground с редактором Monaco (тот же движок, что в VS Code). Есть автодополнение, подсветка синтаксиса, нумерация строк, тёмная тема, Vim-режим. Код выполняется через тот же бэкенд Google — просто интерфейс удобнее. Если вам не хватает комфорта в стандартном Playground — попробуйте.
Godbolt (Compiler Explorer)
godbolt.org — совсем другой инструмент. Он показывает ассемблерный код, в который компилятор превращает ваш Go. Слева — Go-код, справа — машинные инструкции с цветовой привязкой “строка → инструкция”. Для продвинутых, но если любопытно посмотреть, что происходит на уровне процессора — зайдите.
Типичные грабли
1. “HTTP-запрос не работает!”
resp, err := http.Get("https://example.com")// dial tcp: lookup example.com: no such hostВнешняя сеть заблокирована. Playground — для вычислений, не для сетевого I/O. Для тестирования HTTP используйте локальный сервер на localhost (шаблон “HTTP Server”).
2. “time.Now() показывает 2009 год — Playground сломан?”
Нет. Это фича, а не баг. Дата 2009-11-10 — день анонса Go. Фиксированное время обеспечивает детерминизм и кэширование. Эта “ошибка” настолько частая, что по ней даже заведён issue #41626 на GitHub.
3. “rand.Intn() каждый раз выдаёт одно и то же”
С Go 1.20+ генератор случайных чисел инициализируется автоматически, и rand.Intn() должен выдавать разные значения. Но кэш Playground может возвращать сохранённый результат. Измените код хоть чуть-чуть (даже пробел в комментарии) — и увидите другое число.
4. “Код работает в Playground, но не работает локально”
Format в Playground автоматически добавляет недостающие импорты. Если вы скопируете код без импортов в VS Code — он не скомпилируется. Решение: настройте goimports при сохранении в редакторе (мы делали это в уроке про редактор).
5. “Код работает локально, но не работает в Playground”
Проверьте: не использует ли код сеть, файловую систему, аргументы командной строки, CGO или длительные вычисления (больше 5 секунд)? Всё это ограничено в песочнице.
Итоги
| Что | Деталь |
|---|---|
| URL | go.dev/play |
| Run | Компилирует и запускает код на серверах Google |
| Format | Форматирование + автоимпорты (как goimports) |
| Share | Постоянная ссылка на сниппет. Не удаляется. |
| Горячие клавиши | Shift+Enter — Run, Ctrl+Enter — Format |
| Тёмная тема | Есть (переключатель внизу страницы) |
| Сторонние пакеты | Работают через proxy.golang.org |
| Несколько файлов | Формат txtar: -- file.go -- |
| Тесты | Автоматически, если нет func main() |
| Время выполнения | 5 секунд |
| Память | 100 МБ |
| Сеть | Только localhost |
| Файловая система | Виртуальная, только /tmp |
time.Now() | Всегда 2009-11-10 23:00:00 UTC |
Что дальше?
Теперь у вас есть всё для начала: локальный Go с VS Code, понимание компиляции и онлайн-среда для экспериментов. В следующем уроке — Документация и ресурсы: где искать информацию о Go, как читать pkg.go.dev, что такое go doc, и какие материалы стоит держать под рукой.
Источники
- The Go Playground — официальный Playground
- Inside the Go Playground — Andrew Gerrand о внутренней архитектуре
- About the Playground — описание ограничений (секция About внизу страницы)
- golang.org/x/playground — исходный код Playground
- goplay.tools — альтернативный клиент с Monaco Editor
- Compiler Explorer (Godbolt) — Go → ассемблер