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)]
Для типа map или object, как в примере выше, символ 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 может создавать только значение типа object или tuple, но благодаря правилам автоматического преобразования типов в 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 в значение типа set можно использовать функцию toset.
toset([for e in var.set : e.example])
Группировка результатов
Если тип результата — object (разделители { и }), обычно заданное выражение ключа должно возвращать уникальные значения для всех элементов результата, иначе 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.10/language/expressions/for/