for Выражения
Выражение for создает значение сложного типа, преобразуя другое значение сложного типа. Каждый элемент входного значения может соответствовать одному или нулю значений в результате, а для преобразования каждого входного элемента в выходной можно использовать произвольное выражение.
Например, если var.list был бы списком строк, то следующее выражение создало бы кортеж строк, состоящих из заглавных букв:
[for s in var.list : upper(s)]
Это выражение for перебирает каждый элемент var.list, а затем вычисляет выражение upper(s), задавая s значение соответствующего элемента. Затем оно создает новое значение-кортеж, содержащее все результаты выполнения этого выражения в том же порядке.
Типы входных данных
Входными данными выражения for (указанными после ключевого слова in) могут быть список, множество, кортеж, карта или объект.
В приведенном выше примере показано выражение for только с одним временным символом s, однако в выражении for можно указать пару временных символов, чтобы также использовать ключ или индекс каждого элемента:
[for k, v in var.map : length(k) + length(v)]
Для типа «карта» или «объект», как в примере выше, символ k обозначает ключ или имя атрибута текущего элемента. Форму с двумя символами также можно использовать со списками и кортежами; в этом случае дополнительный символ обозначает индекс каждого элемента, начиная с нуля. Обычно для него используют имя символа i или idx, если только для ясности не требуется выбрать более конкретное имя:
[for i, v in var.list : "${i} is ${v}"]Символ индекса или ключа всегда необязателен. Если после ключевого слова for указан только один символ, он всегда будет обозначать значение каждого элемента входной коллекции.
Типы результатов
Тип результата определяется типом скобок, используемых в выражении for.
В приведенном выше примере используются [ и ], в результате чего создается кортеж. Если вместо них использовать { и }, результатом будет объект, для которого необходимо указать два выражения результата, разделенных символом =>:
{for s in var.list : s => upper(s)}Это выражение создает объект, атрибутами которого являются исходные элементы var.list, а соответствующими значениями — их версии в верхнем регистре. Например, итоговое значение может выглядеть так:
{
foo = "FOO"
bar = "BAR"
baz = "BAZ"
}Выражение for само по себе может создавать только значение объекта или кортежа, однако благодаря правилам автоматического преобразования типов OpenTofu результаты обычно можно использовать там, где ожидаются списки, карты и множества.
Фильтрация элементов
Выражение for также может содержать необязательное условие if для фильтрации элементов исходной коллекции. В результате получится значение, содержащее меньше элементов, чем исходное:
[for s in var.list : upper(s) if s != ""]
Часто коллекции фильтруют в выражениях for, чтобы разделить одну исходную коллекцию на две, руководствуясь определенными критериями. Например, если входные данные var.users — это карта объектов, каждый из которых имеет атрибут is_admin, может потребоваться создать отдельные карты для объектов с правами администратора и без них:
variable "users" {
type = map(object({
is_admin = bool
}))
}
locals {
admin_users = {
for name, user in var.users : name => user
if user.is_admin
}
regular_users = {
for name, user in var.users : name => user
if !user.is_admin
}
}Порядок элементов
Поскольку выражения for могут преобразовывать неупорядоченные типы (карты, объекты, множества) в упорядоченные (списки, кортежи), OpenTofu должен определить порядок элементов неупорядоченной коллекции.
Для карт и объектов OpenTofu сортирует элементы по ключу или имени атрибута, используя лексикографическую сортировку.
Для множеств строк OpenTofu сортирует элементы по их значениям, используя лексикографическую сортировку.
Для множеств других типов OpenTofu использует произвольный порядок, который может измениться в будущих версиях. Рекомендуем преобразовывать результат выражения в множество, чтобы в других местах конфигурации было ясно, что результат не упорядочен. Для краткого преобразования результата выражения for в множество можно использовать функцию toset.
toset([for e in var.set : e.example])
Группировка результатов
Если тип результата — объект (с разделителями { и }), то обычно указанное выражение ключа должно возвращать уникальное значение для каждого элемента результата. В противном случае OpenTofu вернет ошибку.
Иногда результирующие ключи не являются уникальными. Для таких случаев OpenTofu поддерживает специальный режим группировки, который позволяет хранить несколько элементов для одного ключа.
Чтобы включить режим группировки, добавьте символ ... после выражения значения. Например:
variable "users" {
type = map(object({
role = string
}))
}
locals {
users_by_role = {
for name, user in var.users : user.role => name...
}
}В примере выше рассматривается ситуация, когда модуль ожидает карту с данными о разных пользователях, у каждого из которых есть одна «роль», а ключами карты являются имена пользователей. Имена пользователей гарантированно уникальны, поскольку в исходных данных они служат ключами карты, однако у многих пользователей может быть одно и то же название роли.
Выражение local.users_by_role инвертирует исходную карту: ключами становятся названия ролей, а значениями — имена пользователей. Однако выражение работает в режиме группировки (из-за символа ... после name), поэтому результатом будет карта списков строк, например:
{
"admin": [
"ps",
],
"maintainer": [
"am",
"jb",
"kl",
"ma",
],
"viewer": [
"st",
"zq",
],
}Согласно правилам порядка элементов, при вычислении выражения for OpenTofu отсортирует пользователей по именам в лексикографическом порядке. Поэтому после группировки имена пользователей, связанные с каждой ролью, также будут отсортированы в лексикографическом порядке.
Повторяющиеся блоки конфигурации
Механизм выражений for предназначен для создания значений коллекций из других значений коллекций внутри выражений. Затем эти значения можно присваивать отдельным аргументам ресурсов, ожидающим сложные значения.
Некоторые типы ресурсов также определяют вложенные типы блоков, которые обычно представляют отдельные объекты, некоторым образом связанные с содержащим их ресурсом. С помощью выражений for нельзя динамически создавать вложенные блоки, но вложенные блоки ресурса можно создавать динамически с помощью блоков dynamic.
Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.9/language/expressions/for/