Você pode definir suas próprias funções personalizadas em jq para encapsular a lógica que precisar.
Funções funcionam igual às funções nativas: elas recebem uma entrada e emitem zero, um ou mais resultados.
Você pode definir uma função jq usando a seguinte sintaxe:
# no arguments
def funcname: expression;
# or with arguments
def funcname(args): expression;
def,jq, você pode usar espaços em branco à vontade para facilitar a leitura.Funções precisam ser definidas antes de serem usadas: isto é um erro:
def A: B(10);
def B(n): n + 1;
A
# => error: B/1 is not defined
Isso significa que você precisa colocar as funções no topo do seu código jq, antes da expressão "principal".
Funções podem ser aninhadas:
def A:
def B(n): n + 1;
B(10)
;
A
# => 11
Aqui, a função B só é visível no corpo de A.
Uma função introduz um novo escopo para variáveis e funções aninhadas.
Os argumentos de uma função são separados por ponto e vírgula, não por vírgulas. Por exemplo, uma função que recebe um número, e depois soma um número e multiplica por um número:
def add_mul(adder; multiplier): (. + adder) * multiplier;
10 | add_mul(5; 4) # => 60
Ponto e vírgula é necessário porque a vírgula já tem uma finalidade no jq: um operador que junta fluxos.
Usar uma vírgula em vez de ponto e vírgula vai tentar fazer duas chamadas a uma função add_mul de 1 argumento, que não existe e, portanto, vai falhar na primeira tentativa de chamada:
10 | add_mul(5, 4)
# error: add_mul/1 is not defined
Os argumentos de uma função são filtros, não valores. Nesse sentido, eles funcionam como o que outras linguagens descrevem como callbacks:
Usando a função add_mul como exemplo:
10 | add_mul(. + 5; . - 2) # => 200
O que está acontecendo aqui?
adder recebe a expressão . + 5
. + adder, isso vira . + . + 5
. == 10
multiplier é a expressão . - 2
25 * 8 == 200
Às vezes você vai querer "materializar" um argumento em uma variável:
def my_func(arg):
arg as $arg
| other stuff ...
;
Existe uma forma abreviada para isso:
def my_func($arg):
other stuff ...
;
Vale notar que isso é apenas "açúcar sintático": o nome arg sem $ continua no escopo dentro da função.
Funções têm uma aridade, ou seja, o número de argumentos que recebem.
Funções podem usar o mesmo nome com aridades diferentes.
A função nativa range demonstra isso: range/1, range/2 e range/3 coexistem.
Isso pode ser útil para definir funções recursivas que carregam estado por meio de argumentos.
Por exemplo, map poderia ser implementado assim:
def my_map($accumulator; func):
if length == 0
then $accumulator
else first as $elem | .[1:] | my_map($accumulator + [$elem | func]; func)
end
;
def my_map(func):
my_map([]; func)
;
[1, 2, 3, 4] | my_map(. * 10) # => [10, 20, 30, 40]
O jq faz otimização de chamadas de cauda, mas apenas para funções de aridade 0.
Um módulo jq é um arquivo contendo apenas funções.
Módulos são incluídos em um programa jq com os comandos include ou import.
Neste exercício, você vai brincar com um carro de controle remoto, para o qual finalmente juntou dinheiro suficiente para comprar.
Os carros começam com a bateria cheia (100%). Cada vez que você dirige o carro usando o controle remoto, ele percorre 20 metros e gasta um por cento da bateria. O apelido do carro só é conhecido quando ele é criado.
O carro de controle remoto tem um display de LED sofisticado que mostra duas informações:
"<METERS> meters"."Battery at <PERCENTAGE>%".Se a bateria estiver em 0%, você não pode mais dirigir o carro e o display da bateria vai mostrar "Battery empty".
Implemente a função new_remote_control_car/0 para retornar um objeto de carro de controle remoto novinho em folha:
new_remote_control_car
# => {
# "battery_percentage": 100,
# "distance_driven_in_meters": 0,
# "nickname": null
# }
Implemente a função new_remote_control_car/1 para retornar um objeto de carro de controle remoto novinho em folha com um apelido fornecido:
new_remote_control_car("Blue")
# => {
# "battery_percentage": 100,
# "distance_driven_in_meters": 0,
# "nickname": "Blue"
# }
Implemente a função display_distance/0 que recebe um objeto de carro como entrada e retorna a string de distância exibida no display de LED:
new_remote_control_car | display_distance
# => "0 meters"
Implemente a função display_battery/0 que recebe um objeto de carro como entrada e retorna a string da porcentagem da bateria exibida no display de LED:
new_remote_control_car | display_battery
# => "Battery at 100%"
Se a bateria estiver em 0%, o display da bateria vai mostrar "Battery empty".
Implemente a função drive/0 que:
new_remote_control_car("Red") | drive
# => {
# "battery_percentage": 99,
# "distance_driven_in_meters": 20,
# "nickname": "Red"
# }
Atualize a função drive/0 para não aumentar a distância percorrida nem diminuir a porcentagem da bateria quando a bateria estiver descarregada (em 0%):
{
battery_percentage: 0,
distance_driven_in_meters: 2000,
nickname: "Red"
} | drive
# => {
# "battery_percentage": 0,
# "distance_driven_in_meters": 2000,
# "nickname": "Red"
# }
Crie sua conta no Exercism para aprender e dominar jq com 12 conceitos75 exercícios e mentoria humana de verdade, tudo de graça.