如何在Jsonnet中通过单条件判断批量生成并合并大型对象?
Jsonnet条件生成对象的冗余代码优化
我需要在条件满足时,创建一个大型对象并合并到现有对象中。当前实现可行但存在冗余的if-then-else语句,希望用单个条件判断完成对象生成。
原始可行代码
local something_something = true; local tst = { n1: { a: "10.172.52.0/22", b: "10.172.56.0/22", }, n2: { c: "10.172.60.0/22", }, }; { aws_route: { public: { route_table_id: '${aws_route_table.public.id}', destination_cidr_block: '0.0.0.0/0', gateway_id: '${aws_internet_gateway.tst.id}', } } + ( if something_something then { ['nat_%s' % zone]: { route_table_id: '${aws_route_table.nat_%s.id}' % zone, destination_cidr_block: '0.0.0.0/0', nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone, } for zone in std.objectFields(tst.n1) } else {}) + ( if something_something then { ['nat_%s' % zone]: { route_table_id: '${aws_route_table.nat_%s.id}' % zone, destination_cidr_block: '0.0.0.0/0', nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone, } for zone in std.objectFields(tst.n2) } else {}) }
预期输出
{ "aws_route": { "nat_a": { "destination_cidr_block": "0.0.0.0/0", "nat_gateway_id": "${aws_nat_gateway.ngw_a.id}", "route_table_id": "${aws_route_table.nat_a.id}" }, "nat_b": { "destination_cidr_block": "0.0.0.0/0", "nat_gateway_id": "${aws_nat_gateway.ngw_b.id}", "route_table_id": "${aws_route_table.nat_b.id}" }, "nat_c": { "destination_cidr_block": "0.0.0.0/0", "nat_gateway_id": "${aws_nat_gateway.ngw_c.id}", "route_table_id": "${aws_route_table.nat_c.id}" }, "public": { "destination_cidr_block": "0.0.0.0/0", "gateway_id": "${aws_internet_gateway.tst.id}", "route_table_id": "${aws_route_table.public.id}" } } }
尝试的错误代码及报错
尝试合并两个for推导式,但语法不支持:
{ aws_route: { public: { route_table_id: '${aws_route_table.public.id}', destination_cidr_block: '0.0.0.0/0', gateway_id: '${aws_internet_gateway.tst.id}', } } + ( if something_something then { ['nat_%s' % zone]: { route_table_id: '${aws_route_table.nat_%s.id}' % zone, destination_cidr_block: '0.0.0.0/0', nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone, } for zone in std.objectFields(tst.n1), ['nat_%s' % zone]: { route_table_id: '${aws_route_table.nat_%s.id}' % zone, destination_cidr_block: '0.0.0.0/0', nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone, } for zone in std.objectFields(tst.n2) } else {}) }
报错信息:
STATIC ERROR: tst.jsonnet:26:41: expected for, if or "}" after for clause, got: ","
解决方案
你的思路是合理的,Jsonnet支持通过合并字段数组后推导对象或提取复用逻辑来消除冗余,以下是两种更优实现方式:
方式1:合并字段数组后推导对象
先把tst.n1和tst.n2的字段合并成一个数组,再用单个for推导生成对象,这样只需一次条件判断:
local something_something = true; local tst = { n1: { a: "10.172.52.0/22", b: "10.172.56.0/22", }, n2: { c: "10.172.60.0/22", }, }; // 合并两个对象的字段数组 local all_zones = std.objectFields(tst.n1) + std.objectFields(tst.n2); { aws_route: { public: { route_table_id: '${aws_route_table.public.id}', destination_cidr_block: '0.0.0.0/0', gateway_id: '${aws_internet_gateway.tst.id}', } } + ( if something_something then { ['nat_%s' % zone]: { route_table_id: '${aws_route_table.nat_%s.id}' % zone, destination_cidr_block: '0.0.0.0/0', nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone, } for zone in all_zones } else {} ) }
方式2:提取复用的路由对象生成逻辑
如果后续需要扩展更多类似的n3、n4,可以把生成单个nat路由的逻辑提取成局部函数,再批量生成后合并:
local something_something = true; local tst = { n1: { a: "10.172.52.0/22", b: "10.172.56.0/22", }, n2: { c: "10.172.60.0/22", }, }; // 提取生成单个nat路由的函数 local make_nat_route(zone) = { ['nat_%s' % zone]: { route_table_id: '${aws_route_table.nat_%s.id}' % zone, destination_cidr_block: '0.0.0.0/0', nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone, } }; // 批量生成并合并所有nat路由对象 local all_nat_routes = std.foldl( (acc, zone) => acc + make_nat_route(zone), std.objectFields(tst.n1) + std.objectFields(tst.n2), {} ); { aws_route: { public: { route_table_id: '${aws_route_table.public.id}', destination_cidr_block: '0.0.0.0/0', gateway_id: '${aws_internet_gateway.tst.id}', } } + (if something_something then all_nat_routes else {}) }
这两种方式都能实现单个条件判断生成所有需要的对象,同时消除代码冗余,第二种方式的扩展性更强,适合后续新增更多区域的场景。
内容的提问来源于stack exchange,提问作者NarūnasK
相关产品推荐
相关产品推荐

