---
sidebar_label: "Подстановка переменных"
title: "Подстановка переменных - CyberGo env | Синтаксис переменных"
description: "Подстановка CyberGo env: ${VAR}, ${VAR:-default}, ${VAR:=default}, ${VAR:?error}, краткая форма $VAR, обнаружение циклов и лимит MaxExpansionDepth."
sidebar_position: 4
---

# Подстановка переменных

Библиотека env поддерживает ссылки на переменные в конфигурационных файлах для повторного использования конфигурации и динамической подстановки значений.

## Включение подстановки переменных

```go
cfg := env.DefaultConfig()
cfg.ExpandVariables = true  // Включено по умолчанию

loader, _ := env.New(cfg)
loader.LoadFiles(".env")
```

## Базовый синтаксис

### Простые ссылки

```bash
# Ссылка на другие переменные
BASE_URL=https://api.example.com
API_URL=${BASE_URL}/v1
# API_URL разворачивается в: https://api.example.com/v1

# Краткий синтаксис
HOST=localhost
URL=$HOST:8080
# URL разворачивается в: localhost:8080
```

### Синтаксис значений по умолчанию

| Синтаксис | Описание |
|------|------|
| `${VAR:-default}` | Если VAR не существует, используется default |
| `${VAR:=default}` | Если VAR не существует, используется default (аналог `:-`) |
| `${VAR:?error}` | Если VAR не существует или пусто, возвращается ошибка |

::: warning Ограничение самообращения
Переменная, на которую ссылаются `:-`, `:=`, `:?`, должна отличаться от ключа, которому присваивается значение. Самообращение вида `KEY=${KEY:-default}` распознаётся как цикл и приводит к ошибке `ErrExpansionDepth` при загрузке. Чтобы задать ключу значение по умолчанию, присвойте литерал напрямую (`KEY=default`) либо сошлитесь на другую переменную (см. примеры ниже).
:::

---

## Подробный синтаксис

### `${VAR:-default}` - Использование значения по умолчанию

Наиболее распространённый синтаксис значений по умолчанию. Когда переменная не существует, используется значение по умолчанию; если переменная существует (даже с пустым значением), используется оригинальное значение:

```bash
# HOST уже определена, используется её значение
HOST=localhost
PRIMARY_HOST=${HOST:-127.0.0.1}
# PRIMARY_HOST разворачивается в: localhost

# Если TIMEOUT не существует, используется значение по умолчанию "30s"
TIMEOUT_VALUE=${TIMEOUT:-30s}
# TIMEOUT_VALUE разворачивается в: 30s

# Вложенные значения по умолчанию
DB_HOST=localhost
DB_URL=${DB_HOST}:${DB_PORT:-5432}
# Если DB_HOST=localhost и DB_PORT не существует
# DB_URL разворачивается в: localhost:5432
```

**Сценарии использования:**
- Значения по умолчанию для необязательных параметров конфигурации
- Единая конфигурация для сред разработки/продакшена

---

### `${VAR:=default}` - Использование значения по умолчанию

Поведение идентично `${VAR:-default}` — когда переменная не существует, используется значение по умолчанию:

```bash
# Если DEBUG не существует, используется "false"
DEBUG_VALUE=${DEBUG:=false}

# Если CACHE_TTL не существует, используется значение по умолчанию
CACHE_TTL_VALUE=${CACHE_TTL:=3600}
```

::: info Связь с `:-`
`${VAR:=default}` в данной библиотеке полностью идентична `${VAR:-default}` по поведению. Когда переменная не существует, в качестве результата подстановки используется значение по умолчанию. `:=` не записывает значение по умолчанию обратно в хранилище переменных.
:::

---

### `${VAR:?error}` - Сообщение об ошибке

Если переменная не существует или пуста, возвращается ошибка:

```bash
# Если DATABASE_URL не существует, загрузка завершится с ошибкой
DB_URL=${DATABASE_URL:?Database URL is required}

# Если API_TOKEN не существует, будет выдана ошибка
AUTH_TOKEN=${API_TOKEN:?API_TOKEN must be set}
```

**Сценарии использования:**
- Валидация обязательных параметров конфигурации
- Ранний отказ для предотвращения ошибок во время выполнения

---

## Экранирование

### Экранирование знака доллара

Используйте `$$` для буквального символа `$`:

```bash
# Конфигурация цены
PRICE=$$99.99
# Разворачивается в: $99.99

# Строка, содержащая $
MESSAGE=Price is $$100
# Разворачивается в: Price is $100
```

### Кавычки и подстановка

Подстановка переменных выполняется на едином этапе постобработки после снятия кавычек, поэтому **ни одинарные, ни двойные кавычки не влияют на подстановку**. Например, `SINGLE='${BASE}'` (при `BASE=hello`) после подстановки даёт значение `hello` — так же, как в двойных кавычках; если ссылочная переменная не определена (например, `LITERAL='${NO_EXPANSION}'`), результатом будет пустая строка, а не литерал `${NO_EXPANSION}`.

Различие между одинарными и двойными кавычками состоит только в **буквальном разборе**: двойные кавычки обрабатывают escape-последовательности вроде `\n`, `\t`, одинарные — сохраняют текст как есть (без экранирования).

:::warning Внимание
Не используйте кавычки для «запрета подстановки». Чтобы сохранить литерал `${VAR}`, используйте следующие способы:
:::

```bash
# Способ 1: экранирование знака доллара ($$ разворачивается в буквальный $)
LITERAL='$${NO_EXPANSION}'
# Значение: ${NO_EXPANSION}
```

```go
// Способ 2: глобальное отключение подстановки переменных
cfg := env.DefaultConfig()
cfg.ExpandVariables = false
```

---

## Вложенная подстановка

Переменные могут содержать вложенные ссылки:

```bash
# Базовая конфигурация (избегайте встроенного запрещённого ключа ENV, используйте DEPLOY_ENV)
APP_NAME=myapp
DEPLOY_ENV=production

# Вложенные ссылки
DB_HOST=db.${DEPLOY_ENV}.example.com
# Разворачивается в: db.production.example.com

API_URL=https://${APP_NAME}.${DEPLOY_ENV}.api.example.com
# Разворачивается в: https://myapp.production.api.example.com
```

---

## Обнаружение циклов

Библиотека автоматически обнаруживает циклические ссылки и возвращает ошибку:

```bash
# Циклическая ссылка (ошибка)
A=${B}
B=${A}

# При загрузке будет возвращена ошибка ErrExpansionDepth
```

---

## Ограничение глубины подстановки

Максимальная глубина подстановки по умолчанию — 5, жёсткий предел — 20:

```go
cfg := env.DefaultConfig()
cfg.MaxExpansionDepth = 10  // Пользовательская глубина
```

| Константа | Значение | Описание |
|------|---|------|
| `DefaultMaxExpansionDepth` | 5 | Значение по умолчанию (публичный API) |

::: info Примечание
Жёсткий предел составляет 20 (внутреннее ограничение). Настроенное значение `MaxExpansionDepth` не может превышать этот предел.
:::

---

## Полный пример

```bash
# Файл .env

# Базовая конфигурация (избегайте встроенного запрещённого ключа ENV)
APP_NAME=myapp
DEPLOY_ENV=development
DEBUG=true

# Конфигурация базы данных
DB_HOST=localhost
DB_PORT=5432
DB_NAME=${APP_NAME}
DB_URL=postgres://${DB_HOST}:${DB_PORT}/${DB_NAME}

# Конфигурация API
API_BASE=https://api.${DEPLOY_ENV}.example.com
API_URL=${API_BASE}/v1

# Конфигурация логирования
LOG_LEVEL=info

# Цена (экранирование)
PRICE=$$99.99
```

```go
package main

import (
    "fmt"
    "log"

    "github.com/cybergodev/env"
)

func main() {
    cfg := env.DefaultConfig()
    cfg.ExpandVariables = true

    loader, err := env.New(cfg)
    if err != nil {
        log.Fatal(err)
    }
    defer loader.Close()

    err = loader.LoadFiles(".env")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("DB_URL:", loader.GetString("DB_URL"))
    fmt.Println("API_URL:", loader.GetString("API_URL"))
    fmt.Println("PRICE:", loader.GetString("PRICE"))
}
```

---

## Связанная документация

- [Быстрый старт](/ru/env/getting-started/) - Базовое использование
- [Config API](/ru/env/api-reference/config) - Конфигурация ExpandVariables
- [Константы и ошибки](/ru/env/api-reference/constants) - Ограничения глубины подстановки
