Saját egyéni függvényeket definiálhatsz a jq-ban, hogy bármilyen logikát egységbe zárj vele.
A függvények pontosan úgy viselkednek, mint a beépített függvények: kapnak egy bemenetet, és nullát, egyet vagy több kimenetet adnak.
A jq-ban a következő szintaxissal definiálhatsz egy függvényt:
# no arguments
def funcname: expression;
# or with arguments
def funcname(args): expression;
def kulcsszóval kezdődik,jq szintaxisának többi részéhez hasonlóan tetszőleges whitespace-t használhatsz az olvashatóság kedvéért.A függvényeket a használatuk előtt kell definiálni: ez hiba:
def A: B(10);
def B(n): n + 1;
A
# => error: B/1 is not defined
Ez azt jelenti, hogy a függvényeket a jq-kódod elejére kell tenned, a „fő” kifejezés elé.
A függvényeket egymásba ágyazhatod:
def A:
def B(n): n + 1;
B(10)
;
A
# => 11
Itt a B függvény csak az A törzsében látható.
Egy függvény új scope-ot vezet be a változók és a beágyazott függvények számára.
A függvény argumentumait pontosvesszők választják el egymástól, nem vesszők. Például egy olyan függvény, amely kap egy számot, majd hozzáad egy számot és megszoroz egy számmal:
def add_mul(adder; multiplier): (. + adder) * multiplier;
10 | add_mul(5; 4) # => 60
A pontosvesszőre azért van szükség, mert a vesszőnek már van egy funkciója a jq-ban: olyan operátor, amely stream-eket kapcsol össze.
Ha vesszőt használsz pontosvessző helyett, azzal két hívást próbálsz indítani egy 1 argumentumos add_mul függvény felé, amely nem létezik, ezért már az első próbált hívásnál hibára fut:
10 | add_mul(5, 4)
# error: add_mul/1 is not defined
A függvények argumentumai filterek, nem értékek. Ebben az értelemben úgy viselkednek, mint amit más nyelvek callbacknek neveznek:
Az add_mul függvényt példaként használva:
10 | add_mul(. + 5; . - 2) # => 200
Mi történik itt?
adder argumentum a . + 5 kifejezést kapja
. + adder műveletet végzi, az . + . + 5 lesz. == 10
multiplier argumentum a . - 2 kifejezés
25 * 8 == 200
Néha szeretnéd egy argumentumból változót „materializálni”:
def my_func(arg):
arg as $arg
| other stuff ...
;
Erre van egy rövidített írásmód:
def my_func($arg):
other stuff ...
;
Vedd figyelembe, hogy ez csupán „szintaktikai cukor”: az arg név $ nélkül is a függvény scope-jában marad.
A függvényeknek van egy aritásuk, vagyis az általuk felvett argumentumok száma.
A függvények ugyanazt a nevet használhatják különböző aritásokkal.
A beépített range függvény jól mutatja ezt: a range/1, range/2 és range/3 mind létezhet egymás mellett.
Ez hasznos lehet olyan rekurzív függvények definiálásához, amelyek argumentumokon keresztül hordozzák az állapotot.
Például a map így is megvalósítható lenne:
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]
A jq elvégzi a farokhívás-optimalizálást, de csak 0 aritású függvények esetében.
A jq modul egy olyan fájl, amely csak függvényeket tartalmaz.
A modulokat az include vagy az import paranccsal illeszted be egy jq programba.
Ebben a feladatban egy távirányítású autóval fogsz játszani, amelyre végre összegyűjtöttél annyi pénzt, hogy megvedd.
Az autók tele (100%-os) akkumulátorral indulnak. Valahányszor elvezeted az autót a távirányítóval, 20 métert tesz meg, és az akkumulátor egy százalékát meríti le. Az autó beceneve a létrehozásáig nem ismert.
A távirányítású autónak van egy menő LED-kijelzője, amely két adatot mutat:
"<METERS> meters"."Battery at <PERCENTAGE>%".Ha az akkumulátor 0%-on van, nem tudod tovább vezetni az autót, és az akkumulátor-kijelző ezt mutatja: "Battery empty".
Valósítsd meg a new_remote_control_car/0 függvényt, amely egy vadonatúj távirányítású autó objektumot ad vissza:
new_remote_control_car
# => {
# "battery_percentage": 100,
# "distance_driven_in_meters": 0,
# "nickname": null
# }
Valósítsd meg a new_remote_control_car/1 függvényt, amely egy vadonatúj, megadott becenevű távirányítású autó objektumot ad vissza:
new_remote_control_car("Blue")
# => {
# "battery_percentage": 100,
# "distance_driven_in_meters": 0,
# "nickname": "Blue"
# }
Valósítsd meg a display_distance/0 függvényt, amely bemenetként egy autó objektumot kap, és visszaadja a LED-kijelzőn megjelenő távolságot jelző szöveget:
new_remote_control_car | display_distance
# => "0 meters"
Valósítsd meg a display_battery/0 függvényt, amely bemenetként egy autó objektumot kap, és visszaadja a LED-kijelzőn megjelenő akkumulátor-töltöttséget jelző szöveget:
new_remote_control_car | display_battery
# => "Battery at 100%"
Ha az akkumulátor 0%-on van, az akkumulátor-kijelző ezt mutatja: „Battery empty”.
Valósítsd meg a drive/0 függvényt, amely:
new_remote_control_car("Red") | drive
# => {
# "battery_percentage": 99,
# "distance_driven_in_meters": 20,
# "nickname": "Red"
# }
Módosítsd a drive/0 függvényt úgy, hogy ne növelje a megtett távolságot, és ne csökkentse az akkumulátor töltöttségét, amikor az akkumulátor lemerült (0%-on van):
{
battery_percentage: 0,
distance_driven_in_meters: 2000,
nickname: "Red"
} | drive
# => {
# "battery_percentage": 0,
# "distance_driven_in_meters": 2000,
# "nickname": "Red"
# }
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) jq nyelvet 12 fogalom75 feladat segítségével, valódi emberi mentorálással, mindez ingyen.