轨道
/
jq
jq
/
练习
/
千层面
千层面

千层面

学习练习

简介

变量

回想一下,jq程序是一条_表达式管道_。 变量赋值遵循这条规则:_变量赋值_是一个像这样的表达式:

... | expr as $varname | ...

过滤器的输出就是输入

和_恒等表达式_.一样,_变量赋值_的输出与它的输入相同。 设置变量的值是一种副作用。

下面这个例子说明,赋值之后的.与最初的输入相同:

$ jq -c -n '42 | (. * 2) as $double | [., $double]'
[42,84]

变量的作用域

变量的作用域是“词法”的,也就是说,变量在管道剩余的部分中都在作用域内。 在函数中定义的变量(我们稍后会讲到函数)是函数的“局部”变量。

变量名

变量必须以$开头。 变量名的其余部分是一个标识符:以字母或下划线开头,后面跟着字母、数字或下划线。

解构赋值

手册中是这么写的:

通过提供一个_与输入的结构相匹配_的模式,可以使用单个as表达式声明多个变量(这称为“解构”)。

示例:

[1, 2, 3] as [$a, $b, $c]
| [$a, $b, $c]     # => [1, 2, 3]
{"foo": "bar", "len": [10, 20]} as {foo: $f, len: [$h, $w]}
| [$f, $h, $w]     # => ["bar", 10, 20]

让变量名与_对象的键_匹配,可以获得一种简写:

{"x": 4, "y": 7} as {$x, $y}
| [$x, $y]         # => [4, 7]
{"foo": "bar", "len": [10, 20]} as {$foo, $len}
| [$foo, $len]     # => ["bar", [10, 20]]
Note

同样的简写反过来也适用于_对象的构造_

4 as $x | 7 as $y | {$x, $y}    # => {"x":4, "y": 7}

常量

如上面的例子所示,用变量来存储常量很方便。 与其让“魔法数字”出现在代码中,不如给常量起个名字。

往往并不需要变量

省略变量通常会让代码更易读。

以计算一组数字的平均值为例:

[2, 4, 8, 7]
| add as $sum
| length as $len
| $sum / $len

与下面这种写法相比:

[2, 4, 8, 7] | add / length

这体现了jq最强大的特性之一:过滤器的输入会提供给_每一个_子表达式:

  • 输入数组[2,4,8,7]被传给add(它把+运算符应用到所有元素上,从而求出这些数字的和)
  • 同时,[2,4,8,7]也会被传给length
  • 当这些子表达式完成后,它们的结果会被相除,返回输入数组中所有数字的平均值。

学习练习会用到的jq运算符

替代运算符://

表达式a // b在a为 false 或 null 时输出b,否则输出a。 在给变量赋值的场景中,它非常适合用来提供默认值:

(.input.theAnswer // 42) as $answer | ...
算术运算符
  • +、-、* 就是常见的数值加法、减法和乘法运算符。

说明

在这个练习中,你将编写一些代码,帮助你按照最喜欢的烹饪书做出一份美味的千层面。

你有四个任务,全都与烹饪千层面所花的时间有关。

1. 定义烤箱的预期时间(分钟)

定义一个名为$expected_minutes_in_oven的常量。 根据烹饪书,烤箱的预期时间是 40 分钟:

$ jq -n -f lasagna.jq
{
  "expected_minutes_in_oven": 40,
  ...

2. 计算烤箱的剩余时间(分钟)

这个值接收千层面在烤箱中实际已经烤制的分钟数作为输入,并根据上一个任务中得出的烤箱预期时间,返回千层面还需要在烤箱中继续烤制多少分钟:

$ echo '{"actual_minutes_in_oven": 18}' | jq -f lasagna.jq
{
  "expected_minutes_in_oven": 40,
  "remaining_minutes_in_oven": 22,
  ...

3. 计算准备时间(分钟)

准备时间是指把千层面放进烤箱之前,准备好它所需要的时长。 每一层需要 2 分钟来准备。

$ echo '{"number_of_layers": 3}' | jq -f lasagna.jq
{
  ...
  "preparation_time": 6,
  ...

4. 计算总工作时间(分钟)

计算你烹饪千层面总共花了多少分钟。 它等于准备时间的分钟数,加上千层面此刻已经在烤箱中烤制的分钟数。

$ echo '{"actual_minutes_in_oven": 10, "number_of_layers": 2}' | jq -f lasagna.jq
{
  ...
  "total_time": 14,
  ...
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
jq Exercism

准备好开始 千层面 了吗?

注册 Exercism,借助 12 个概念75 个练习 和真人导师指导,学习并掌握 jq,全部免费。