1"use strict";(globalThis.webpackChunkwebsite=globalThis.webpackChunkwebsite||[]).push([[412],{19511(e,s,n){n.r(s),n.d(s,{assets:()=>r,contentTitle:()=>l,default:()=>p,frontMatter:()=>a,metadata:()=>t,toc:()=>c});let t=JSON.parse('{"id":"language/expressions/splat","title":"Splat Expressions","description":"Splat expressions concisely represent common operations. In OpenTofu, they also transform single, non-null values into a single-element tuple.","source":"@site/docs/language/expressions/splat.mdx","sourceDirName":"language/expressions","slug":"/language/expressions/splat","permalink":"/docs/language/expressions/splat","draft":false,"unlisted":false,"editUrl":"https://github.com/opentofu/opentofu/edit/v1.13/website/docs/language/expressions/splat.mdx","tags":[],"version":"current","frontMatter":{"description":"Splat expressions concisely represent common operations. In OpenTofu, they also transform single, non-null values into a single-element tuple."},"sidebar":"defaultSidebar","previous":{"title":"References to Named Values","permalink":"/docs/language/expressions/references"},"next":{"title":"Strings and Templates","permalink":"/docs/language/expressions/strings"}}');var i=n(74848),o=n(28453);let a={description:"Splat expressions concisely represent common operations. In OpenTofu, they also transform single, non-null values into a single-element tuple."},l="Splat Expressions",r={},c=[{value:"Splat Expressions with Maps",id:"splat-expressions-with-maps",level:2},{value:"Single Values as Lists",id:"single-values-as-lists",level:2},{value:"Legacy (Attribute-only) Splat Expressions",id:"legacy-attribute-only-splat-expressions",level:2}];function h(e){let s={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(s.header,{children:(0,i.jsx)(s.h1,{id:"splat-expressions",children:"Splat Expressions"})}),"\n",(0,i.jsxs)(s.p,{children:["A ",(0,i.jsx)(s.em,{children:"splat expression"})," provides a more concise way to express a common\noperation that could otherwise be performed with a ",(0,i.jsx)(s.code,{children:"for"})," expression."]}),"\n",(0,i.jsxs)(s.p,{children:["If ",(0,i.jsx)(s.code,{children:"var.list"})," is a list of objects that all have an attribute ",(0,i.jsx)(s.code,{children:"id"}),", then\na list of the ids could be produced with the following ",(0,i.jsx)(s.code,{children:"for"})," expression:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-hcl",children:"[for o in var.list : o.id]\n"})}),"\n",(0,i.jsxs)(s.p,{children:["This is equivalent to the following ",(0,i.jsx)(s.em,{children:"splat expression:"})]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-hcl",children:"var.list[*].id\n"})}),"\n",(0,i.jsxs)(s.p,{children:["The special ",(0,i.jsx)(s.code,{children:"[*]"})," symbol iterates over all of the elements of the list given\nto its left and accesses from each one the attribute name given on its\nright. A splat expression can also be used to access attributes and indexes\nfrom lists of complex types by extending the sequence of operations to the\nright of the symbol:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-hcl",children:"var.list[*].interfaces[0].name\n"})}),"\n",(0,i.jsxs)(s.p,{children:["The above expression is equivalent to the following ",(0,i.jsx)(s.code,{children:"for"})," expression:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-hcl",children:"[for o in var.list : o.interfaces[0].name]\n"})}),"\n",(0,i.jsx)(s.h2,{id:"splat-expressions-with-maps",children:"Splat Expressions with Maps"}),"\n",(0,i.jsxs)(s.p,{children:["The splat expression patterns shown above apply only to lists, sets, and\ntuples. To get a similar result with a map or object value you must use\n",(0,i.jsxs)(s.a,{href:"/docs/language/expressions/for",children:[(0,i.jsx)(s.code,{children:"for"})," expressions"]}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["Resources that use the ",(0,i.jsx)(s.code,{children:"for_each"})," argument will appear in expressions as a map\nof objects, so you can't use splat expressions with those resources.\nFor more information, see\n",(0,i.jsx)(s.a,{href:"/docs/language/meta-arguments/for_each#referring-to-instances",children:"Referring to Resource Instances"}),"."]}),"\n",(0,i.jsx)(s.h2,{id:"single-values-as-lists",children:"Single Values as Lists"}),"\n",(0,i.jsx)(s.p,{children:"Splat expressions have a special behavior when you apply them to a value that\nisn't a list, set, or tuple."}),"\n",(0,i.jsxs)(s.p,{children:["If the value is anything other than a
1null value then the splat expression will\ntransform it into a single-element list, or more accurately a single-element\ntuple value. If the value is ",(0,i.jsx)(s.em,{children:"null"})," then the splat expression will return an\nempty tuple."]}),"\n",(0,i.jsxs)(s.p,{children:["This special behavior can be useful for modules that accept optional input\nvariables whose default value is ",(0,i.jsx)(s.code,{children:"null"})," to represent the absence of any value. This allows the module to adapt the variable value for OpenTofu language features designed to work with collections. For example:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{children:'variable "website_setting" {\n type = object({\n index_document = string\n error_document = string\n })\n default = null\n}\n\nresource "aws_s3_bucket" "example" {\n # ...\n\n dynamic "website" {\n for_each = var.website_setting[*]\n content {\n index_document = website.value.index_document\n error_document = website.value.error_document\n }\n }\n}\n'})}),"\n",(0,i.jsxs)(s.p,{children:["The above example uses a ",(0,i.jsxs)(s.a,{href:"/docs/language/expressions/dynamic-blocks",children:[(0,i.jsx)(s.code,{children:"dynamic"})," block"]}),", which\ngenerates zero or more nested blocks based on a collection value. The input\nvariable ",(0,i.jsx)(s.code,{children:"var.website_setting"})," is defined as a single object that might be null,\nso the ",(0,i.jsx)(s.code,{children:"dynamic"})," block's ",(0,i.jsx)(s.code,{children:"for_each"})," expression uses ",(0,i.jsx)(s.code,{children:"[*]"})," to ensure that\nthere will be one block if the module caller sets the website argument, or\nzero blocks if the caller leaves it set to null."]}),"\n",(0,i.jsxs)(s.p,{children:["This special behavior of splat expressions is not obvious to an unfamiliar\nreader, so we recommend using it only in ",(0,i.jsx)(s.code,{children:"for_each"})," arguments and similar\nsituations where the context implies working with a collection. Otherwise,\nthe meaning of the expression may be unclear to future readers."]}),"\n",(0,i.jsx)(s.h2,{id:"legacy-attribute-only-splat-expressions",children:"Legacy (Attribute-only) Splat Expressions"}),"\n",(0,i.jsx)(s.p,{children:"Earlier versions of the OpenTofu language had a slightly different version\nof splat expressions, which OpenTofu continues to support for backward\ncompatibility. This older variant is less useful than the modern form described\nabove, and so we recommend against using it in new configurations."}),"\n",(0,i.jsxs)(s.p,{children:['The legacy "attribute-only" splat expressions use the sequence ',(0,i.jsx)(s.code,{children:".*"}),", instead of\n",(0,i.jsx)(s.code,{children:"[*]"}),":"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{children:"var.list.*.interfaces[0].name\n"})}),"\n",(0,i.jsxs)(s.p,{children:["This form has a subtly different behavior, equivalent to the following\n",(0,i.jsx)(s.code,{children:"for"})," expression:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{children:"[for o in var.list : o.interfaces][0].name\n"})}),"\n",(0,i.jsxs)(s.p,{children:["Notice that with the attribute-only splat expression the index operation\n",(0,i.jsx)(s.code,{children:"[0]"})," is applied to the result of the iteration, rather than as part of\nthe iteration itself. Only the attribute lookups apply to each element of\nthe input. This limitation was confusing some people using older versions of\nOpenTofu and so we recommend always using the new-style splat expressions,\nwith ",(0,i.jsx)(s.code,{children:"[*]"}),", to get the more consistent behavior."]})]})}function p(e={}){let{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,i.jsx)(s,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},28453(e,s,n){n.d(s,{R:()=>a,x:()=>l});var t=n(96540);let i={},o=t.createContext(i);function a(e){let s=t.useContext(o);return t.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function l(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),t.createElement(o.Provider,{value:s},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.