Перейти к содержимому

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!
4
Go рулит

Знакомо, правда? Всё то же самое, что мы делали в уроке 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 example
go 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 UTC

Playground всегда возвращает одну и ту же дату: 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 PlaygroundVS 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 секунд)? Всё это ограничено в песочнице.


Итоги

ЧтоДеталь
URLgo.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, и какие материалы стоит держать под рукой.


Источники