length / keys / values / contains — コレクション検査関数

1. 概要

  • length — 文字列・リスト・mapの長さを返す
  • keys — mapのキー一覧をリストで返す
  • values — mapの値一覧をリストで返す
  • contains — リストやsetに値が含まれるか判定する
  • 各関数の実用パターンと組み合わせ例

これらの関数はコレクション(list・set・map)やmapの内容を検査するために使います。lengthによる件数チェック、keys/valuesによるmap操作、containsによる存在確認が主な用途です。


2. length — 長さを取得する

length(value)は、文字列の文字数、リスト/setの要素数、mapのキー数を返します。

# terraform consoleで確認
> length("hello")
5

> length(["a", "b", "c"])
3

> length({"a" = 1, "b" = 2})
2

> length([])
0

変数バリデーションでの使用

terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

variable "allowed_ports" {
  description = "許可するポート番号のリスト(最大10件)"
  type        = list(number)
  default     = [80, 443]

  validation {
    condition     = length(var.allowed_ports) >= 1 && length(var.allowed_ports) <= 10
    error_message = "allowed_portsは1〜10件の範囲で指定してください。"
  }
}

variable "bucket_name" {
  description = "S3バケット名(3〜63文字)"
  type        = string

  validation {
    condition     = length(var.bucket_name) >= 3 && length(var.bucket_name) <= 63
    error_message = "バケット名は3〜63文字にしてください。"
  }
}

countとの組み合わせ

variable "subnet_ids" {
  description = "サブネットIDのリスト"
  type        = list(string)
}

data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

resource "aws_instance" "web" {
  # サブネット数分のインスタンスを作成
  count = length(var.subnet_ids)

  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"
  subnet_id     = var.subnet_ids[count.index]

  root_block_device {
    volume_size = 20
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = format("%s-web-%02d", var.environment, count.index + 1)
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

3. keys / values — mapのキーと値を取り出す

keys(map)はmapのキー一覧をソート済みリストで返し、values(map)は値一覧をキーのソート順で返します。

# terraform consoleで確認
> keys({ b = 2, a = 1, c = 3 })
["a", "b", "c"]   # アルファベット順でソートされる

> values({ b = 2, a = 1, c = 3 })
[1, 2, 3]   # keysのソート順(a=1, b=2, c=3)に対応した値

> keys({})
[]

ポイント: values(map)はmapに定義された順序ではなく、keys(map)のアルファベット順に対応した値を返します。順序に依存する処理では注意が必要です。

mapから環境名一覧を取得する

variable "environment_configs" {
  description = "環境ごとの設定"
  type = map(object({
    instance_type = string
    volume_size   = number
  }))
  default = {
    dev = { instance_type = "t3.micro",  volume_size = 20 }
    stg = { instance_type = "t3.small",  volume_size = 50 }
    prd = { instance_type = "t3.medium", volume_size = 100 }
  }
}

locals {
  # 環境名の一覧を取得
  environment_names = keys(var.environment_configs)
  # → ["dev", "prd", "stg"](ソート済み)

  # 全インスタンスタイプの一覧
  instance_types = values({ for k, v in var.environment_configs : k => v.instance_type })
}

output "environments" {
  value = local.environment_names
}

keys + for_each でリソースを動的生成する

resource "aws_s3_bucket" "env_buckets" {
  # mapのキー(環境名)でfor_each
  for_each = var.environment_configs

  bucket = "myapp-${each.key}-data"

  tags = {
    Name        = "myapp-${each.key}-data"
    Environment = each.key
    ManagedBy   = "terraform"
  }
}

output "bucket_names" {
  # 全バケット名をkeys順で表示
  value = [for env in keys(var.environment_configs) : aws_s3_bucket.env_buckets[env].bucket]
}

4. contains — 値が含まれるか判定する

contains(list, value)は、listまたはsetにvalueが含まれる場合trueを返します。

# terraform consoleで確認
> contains(["dev", "stg", "prd"], "prd")
true

> contains(["dev", "stg", "prd"], "prod")
false

> contains([1, 2, 3], 2)
true

> contains([], "any")
false

validationブロックでの使用(最頻出パターン)

variable "environment" {
  description = "環境名(dev/stg/prd のいずれか)"
  type        = string
  default     = "dev"

  validation {
    condition     = contains(["dev", "stg", "prd"], var.environment)
    error_message = "environmentはdev、stg、prdのいずれかを指定してください。"
  }
}

variable "instance_type" {
  description = "EC2インスタンスタイプ"
  type        = string
  default     = "t3.micro"

  validation {
    condition     = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type)
    error_message = "instance_typeはt3.micro/t3.small/t3.mediumのいずれかを指定してください。"
  }
}

条件分岐での使用

locals {
  # 本番環境かどうか判定
  is_production = contains(["prd", "production"], var.environment)

  # 本番のみ詳細ログを有効化
  enable_detailed_logging = local.is_production ? true : false
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = var.instance_type

  root_block_device {
    volume_size = local.is_production ? 100 : 20
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "${var.environment}-app"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

contains と index の使い分け: containsは「存在するか否か」を判定し、index(list, value)は「何番目にあるか」を返します。インデックスが不要な場合はcontains、位置も必要な場合はindexを使います。


5. 関連するコレクション検査関数

関数説明
length(v)長さ/件数を返すlength(["a","b"])2
keys(map)キー一覧(ソート済みlist)を返すkeys({b=2,a=1})["a","b"]
values(map)値一覧(keysのソート順)を返すvalues({b=2,a=1})[1,2]
contains(list, val)値が含まれるか判定contains(["a","b"],"a")true
index(list, val)値の最初のインデックスを返すindex(["a","b"],"b")1
lookup(map, key, default)mapからキーで取得lookup({a=1},"b",0)0

6. 関連記事


7. まとめ

  • length(value) — 文字列の文字数、リスト/setの要素数、mapのキー数を返す。validationやcountとの組み合わせが典型
  • keys(map) — mapのキーをアルファベット順のリストで返す
  • values(map) — mapの値をkeysのソート順のリストで返す(定義順ではない点に注意)
  • contains(list, value) — リスト/setに値が含まれるか判定。validationブロックでの選択肢チェックに最適
  • これらはvalidationブロック・countfor_eachfor式と組み合わせて使うことが多い

動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/functions/length