length, размер коллекции
Работает на list, set, map и string:
length(["a", "b", "c"]) # 3
length(toset(["a", "b", "b"])) # 2 (дубликат убирается)
length({a = 1, b = 2}) # 2length("hello") # 5Полезно для условий и валидации:
validation {condition = length(var.azs) >= 2
error_message = "Минимум 2 availability zone."
}
lookup, значение по ключу с default
lookup({a = 1, b = 2}, "a") # 1lookup({a = 1, b = 2}, "missing") # ошибкаlookup({a = 1, b = 2}, "missing", 0) # 0 (третий арг = default)Третий аргумент, fallback, если ключ не найден. Без него lookup упадёт. На практике почти всегда дают default.
Современный шорткат, map["key"]:
var.tags["Environment"] # как lookup, но без default, упадёт если нет
try(var.tags["Environment"], "") # с default через try
merge, объединение map
Несколько map'ов в один, последующие перекрывают предыдущие:
merge(
{ Project = "demo", Owner = "team" }, { Owner = "platform", Env = "prod" })
# {# Project = "demo"
# Owner = "platform" # перебито
# Env = "prod"
# }
Главный кейс, common_tags + специфичные:
locals { common_tags = { Project = var.project, ManagedBy = "terraform" }}
resource "aws_s3_bucket" "logs" {bucket = "logs-bucket"
tags = merge(local.common_tags, {Purpose = "logs"
})
}
concat, склейка list
concat(["a", "b"], ["c", "d"]) # ["a", "b", "c", "d"]
concat(var.base_cidrs, var.extra_cidrs) # склейка двух списков CIDR
Порядок сохраняется. Дубликаты не убираются (если нужно, заверните в distinct).
flatten, раскрыть вложенные list
Часто результат for-expression или нескольких concat, массив массивов. flatten делает плоский список:
flatten([["a", "b"], ["c"], [], ["d", "e"]])
# ["a", "b", "c", "d", "e"]
Типичный кейс: собрать все IP всех инстансов всех групп:
locals {all_private_ips = flatten([
for asg in aws_autoscaling_group.tiers : asg.target_group_arns
])
}
Раскрывает только один уровень. Если внутри есть ещё вложения, flatten(flatten(...)).
keys, values, части map
keys({a = 1, b = 2, c = 3}) # ["a", "b", "c"] (отсортированы по ключу)values({a = 1, b = 2, c = 3}) # [1, 2, 3] (в том же порядке)keys всегда возвращает отсортированный список, это удобно для стабильных результатов в plan.
contains, проверка наличия
contains(["dev", "staging", "prod"], var.env)
# true / false
Самая частая роль, в validation:
validation {condition = contains(["dev", "staging", "prod"], var.env)
error_message = "env должен быть dev/staging/prod."
}
Для map нет contains. Используйте contains(keys(map), "k") или try(map["k"], null) != null.
distinct, убрать дубликаты
distinct(["a", "b", "a", "c", "b"]) # ["a", "b", "c"]
Порядок сохраняется (первое вхождение). Альтернатива, toset(...), но toset теряет порядок.
element и slice
element(["a", "b", "c"], 1) # "b"
element(["a", "b", "c"], 5) # "c", wraps around: 5 % 3 = 2
slice(["a", "b", "c", "d"], 1, 3) # ["b", "c"], [start, end)
element оборачивается по модулю, это специфика. Если нужна жёсткая ошибка при выходе за границы, используйте list[index].
zipmap, собрать map из двух list
zipmap(["a", "b", "c"], [1, 2, 3])
# {a = 1, b = 2, c = 3}Длины должны совпадать, иначе ошибка.
for-expression, мощнее всех функций
# list → list
[for s in ["dev", "prod"] : upper(s)]
# ["DEV", "PROD"]
# list → map
{ for s in ["dev", "prod"] : s => "bucket-${s}" }# {dev = "bucket-dev", prod = "bucket-prod"}# с фильтром
[for s in var.envs : s if s != "test"]
for-expression покрывает большинство трансформаций. Многие из встроенных функций (keys, values, иногда merge) могут быть переписаны через for.
Подводные камни
-
mergeплоский. Если значения сами map'ы, они перезаписываются, не сливаются. Для глубокого merge, несколькоmergeили вручную через for-expression. -
concatне дедуплицирует. Если нужно объединить и убрать дубли,distinct(concat(a, b)). -
lookupбез default, взрыв. Всегда указывайте третий аргумент или используйтеtry(). -
flattenидёт на один уровень. Двойная вложенность,flatten(flatten(arr)). -
keysсортирует, это хорошо для стабильности. Если нужен оригинальный порядок ключей map, это in вообще проблема, потому что HCL-map неупорядочен по природе. Используйте список объектов. -
elementоборачивается, аlist[index], нет.element(arr, 999)даст результат по модулю.arr[999]упадёт. Для безопасной выборки,try(arr[index], default). -
containsстрого типизирован.contains([1, 2, 3], "1")упадёт,"1"это string,1это number. Приведите типы явно. -
forс map требует уникальных ключей.{ for s in arr : key_func(s) => ... }, если key_func даст одинаковый ключ для двух элементов, упадёт. Лечитсяfor ... if condили сменой ключа.