A nyelv alapvetően kétféle adattípust tud kezelni:
int
32 biten tárolt előjeles egész szám. Használható rá minden beépített aritmetikai, bitenkénti és logikai operátor. Nincs a nyelvben külön logikai típus, ennek megvalósítása egy az egyben az int típussal történik (0 - hamis, 1 - igaz). Minta |
Példa |
Leírás |
-?[1-9][0-9]* |
78 |
Decimális szám |
-?0[0-9]* |
0116 |
Oktális szám |
-?0[xX][0-9a-fA-F]+ |
0x4e |
Hexadecimális szám |
-?0[bB][01]+ |
0b1001110 |
Bináris szám |
-?'\\?.' |
'N' |
ASCII karakter |
A fentiek mindegyike a 78-as decimális számot jelenti.
Egész osztás van a nyelvben, és ez mindig az alsó egész részt jelenti. Egész hatványozás is van: int pow(int alap,int kit)
Egyéb függvények:
int intp(mixed x) |
1-gyel tér vissza, ha x egy int, egyébként 0-val. |
int random(int x) |
0<=szám<x véletlen értékkel tér vissza. |
int reverse(int x) |
Megfordítja x bitjeit. (Mire való?!) |
int sqrt(int x) |
x gyöke. |
float
32 biten tárolt lebegőpontos szám, mely 9 jegy pontosságú. Ha nagyobb pontossággal definiálunk egy literált, akkor azt a legtöbb architektúrán levágja.
A float literálok lehetséges megadásai:
Minta |
Példa |
Mit jelent? |
-?[0-9]+\.[0-9]+ |
3.1415926 |
3.1415926 |
-?[0-9]+e-?[0-9]+ |
-5e3 |
-5000.0 |
-?[0-9]+\.[0-9]+e-?[0-9]+ |
1.022e-2 |
0.01022 |
Használható rá aritmetikai és logikai operátor, és a következő függvények:
Trigonometrikus függvények
A trigonometrikus függvények: szinusz(sin
), arkusz szinusz(asin
),
koszinusz(cos
), ark. kosz.(acos
), tan
és atan
használhatóak.
float log(float x) |
x természetes alapú logaritmusával tér vissza. |
float exp(float x) |
e-alapú hatványozás. |
float pow(float|int x , float|int
y) |
x^y -nal tér vissza. |
float sqrt(float x) |
x gyökét adja. (mint az int-nél) |
float floor(float x) |
A legnagyobb int érték, ami kisebb vagy egyenlő, mint x. Vigyázni: a visszatérési érték nem int, hanem float! |
float ceil(float x) |
A legkisebb int érték, ami nagyobb vagy egyenlő, mint x. Ezt is float-ként! |
float round(float x) |
Matematikai kerekítés. |
string
A string, vagy karakterlánc tulajdonképpen 0-tól 232 - 1-ig terjedő értékek (illetve ilyen értékek által reprezentált karakterek) tömbje. Tartalmazhat szavakat, mondatokat, egy oldalt, vagy akár egy egész könyvet is, de tartalmazhatja egy bináris file részleteit, tömörített adatot, vagy egyéb bináris adatot. Pike-ban a karakterláncok osztottan tárolódnak, ami azt jelenti, hogy a megegyező karakterláncok ugyanazon a memóriahelyen tartózkodnak, így a legtöbb esetben jelentősen csökken a memóriahasználat és gyorsul a karakterláncok összehasonlítása.
Néhány példa:
"hello world" |
// hello world |
"he" "llo" |
// hello |
"\116" |
// N (116 oktális ASCII érték) |
"\t" |
// tab karakter |
"\n" |
// newline karakter |
"\r" |
// kocsivissza karakter |
"\b" |
// backspace karakter |
"\0" |
// null karakter |
"\"" |
// idézőjel |
"\\" |
// backslash |
"\x4e" |
// N (4e hexadecimális ASCII érték) |
"\d78" |
// N (78 decimális ASCII érték) |
"hello world\116\t\n\r\b\0\"\\" |
// vegyes |
"\xff" |
// 255-ös karakter |
"\xffff" |
// 65536-os karakter |
"\xffffff" |
// 16777215 |
"\116""3" |
// 'N' után '3' |
Szekvencia |
ASCII kód |
Karakter |
\b |
8 |
Backspace karakter |
\t |
9 |
Tabulátor karakter |
\n |
10 |
Újsor karakter |
\r |
13 |
Kocsivissza karakter |
\" |
34 |
Idézőjel karakter |
\\ |
92 |
Backslash karakter |
Minden, (dupla) idézőjelek közé zárt karaktersorozat string. A backslash karakter és escape szekvenciák segítségével lehet meg nem jeleníthető vagy be nem gépelhető karaktereket megadni, mint például \t-t a tabulátor, \\ -t a backslash, valamint \" -t a dupla idézőjel helyett. Ezen kívül \XXX alakban bármilyen 0 és 37777777777 közötti oktális, \xXX alakban bármilyen 0 és FFFFFFFF közötti hexadecimális, és \dXXX alakban bármilyen 0 és 232 - 1 közötti decimális kódú karakter megadása lehetséges.
Habár a 0 és 232 - 1 lehetséges érték memóriahasználat szempontjából soknak tűnhet, a Pike azonban automatikusan meghatározza a karakterláncban található karaktereknek szükséges tárat, így például egy 0 és 255 közötti kódú karakterekből álló string karakterenként csupán egy byte-ot foglal. Azonban vigyázni kell, mivel nem minden függvény képes az egy byte-os mérettől eltérő karaktereket kezelni.
Bármennyire is hasonlítson a karakterlánc típus egy tömbre, lényeges eltérés, hogy a karakterlánc nem változtatható meg. Ez annyit jelent, hogy még egy karakter cseréjére sincs mód új karakterlánc létrehozása nélkül. A korábbiak fényében ez érthető, hiszen különben az osztott tárolás miatt az összes azonos karaktereket tartalmazó karakterlánc megváltozna. Ennek ellenére az alábbihoz hasonló kód engedélyezett, és működik:
Azonban ennek eredményeként egy új karakterlánc keletkezik, benne a megváltozott karakterrel. Ez egyben azt jelenti, hogy a fenti művelet hosszú karakterláncoknál meglehetősen lassú lehet.
Karakterláncokon az összehasonlítás operátorokon kívül még más operátorokat is használhatunk
Karakterláncokkal dolgoznak az alábbi függvények:
string String.capitalize(string s) |
s -nek első betűjét nagybetűre cseréli. |
int String.count(string haystack, string needle) |
Visszaadja, hogy hányszor fordul elő átfedés nélkül a needle a haystack-ben. |
int String.width(string s) |
Visszaadja s szélességét, azaz azt, ahány biten s karakterei tárolódnak (8, 16, vagy 32) |
string lower_case(string s) |
s kisbetűsített változatát adja vissza. |
string replace(string s, string mit, string mire) |
Kicseréli s -ben mit mire -re. |
string reverse(string s) |
s fordítottját adja vissza. |
int search(string haystack, string needle) |
Megkeresi a needle-t a haystack-ben, és visszaadja az első előfordulás helyét. |
int strlen(string s) |
s hosszát adja vissza. |
int sizeof(string s) |
Az strlen -hez hasonlóan s hosszát adja vissza. |
int stringp(mixed s) |
1-et ad vissza, ha string , 0-t különben. |
string upper_case(string s) |
s nagybetűsített változatát adja vissza. |
A Pike mutató típusoknak nevezi az összetett típusokat: a tömböt (array), az asszociatív tárolót (mapping), a multihalmazt (multiset), a programot, az objektumot és a függvényt. Ezek mind mutatók, azaz egy memóriában található "dologra" mutatnak, egyre akár többen is, és ez a "dolog" akkor szabadul fel, ha nem mutat rá több mutató. Így tehát értékadáskor sem a memóriában található "dolog" másolódik át, csupán a rá mutató referencia.
Különös gonddal kell eljárni függvények mutatóval való paraméterezésekor, ugyanis ekkor a függvény képes a memóriacímen található "dolog" megváltoztatására. Ezt elkerülendő explicit módon lehetséges a "dolog" közvetlen, érték szerinti átadása.
tömb(array)
A tömbök a legegyszerűbb mutatótípusok. Maga a tömb csupán a memória egy fix méretű darabja, mely bármilyen adat tárolására képes mezőkből áll. Ezek a mezők az elemek, és az indexelés operátoron keresztül érhetők el. Konstans tömb a ({ és }) jelek közé zárva hozható létre, mint például a következők:
({ }) |
// Üres tömb |
({ 1 }) |
//Egy int típusú értéket tartalmazó tömb |
({ "" }) |
//Egy stringet tartalmazó tömb |
({ "", 1, 3.0 }) |
//Három különböző típusú elemet tartalmazó tömb |
Mint látható, a tömb bármelyik eleme bármilyen típusú adatot tárolhat. Indexelés és részsorozatképzés a karakterláncokhoz hasonlóan történik, azzal a különbséggel, hogy az indexelés operátorral megváltoztatható a tömb adott eleme. Nem változtatható viszont a tömb mérete, tehát ha új elemek hozzáadására van szükség, az egész tömböt hozzá kell adni egy másikhoz, mellyel egy új tömb jön létre.
Tömbökkel használható operátorok és függvények.
Az indexelés visszaadja vagy megváltoztatja a tömb adott elemét. A c indexnek integer típusúnak kell lennie. A tömb értékének megváltoztatásához egyszerűen tegyük az egészet az értékadás bal oldalára, például így: t [ c ] = uj_ertek
indexelés(t [ c ])
részsorozat(t [ tol .. ig ])
A részsorozat a t tol, tol + 1, .., ig indexű elemeit egy új tömbbe másolja, melynek a mérete így ig - tol + 1 lesz.
összehasonlítás(a == b illetve a != b)
Az egyenlőséget vizsgáló operátor visszatérési értéke 1 akkor és csak akkor, ha a és b ugyanaz a tömb. Tehát nem elég, ha méretük és tartalmuk megegyezik, a két mutatónak ugyanarra a tömbre kell mutatnia. Például ({1}) == ({1}) visszatérési értéke 0, míg array(int) a=({1}); return a == a; visszatérési értéke 1. Figyelem, tömbökön nem használhatók a >, >=, <, vagy <= operátorok.
Összeadás(a + b)
A karakterláncokhoz hasonlóan az összeadás egymáshoz fűzi, konkatenálja a tömböket. ({1})+({2}) visszatérési értéke így ({1,2}).
Kivonás (a - b)
A kivonás az első tömbből eltávolítja a másodikban előforduló összes elemet. Tehát például {1,3,8,3,2}) - ({3,1}) eredménye ({8,2}).
Metszet (a & b)
A metszet eredménye azon elemek tömbje, amelyek mind a-ban, mind b-ben előfordulnak. Az elemek sorrendje olyan lesz, ahogy a-ban előfordultak. Például ({1,3,7,9,11,12}) & ({4,11,8,9,1}) eredménye ({1,9,11}).
Unió (a | b)
Az unió majdnem ugyanazt eredményezi mint az összeadás, de csak azokat az elemeket adja hozzá a-hoz, melyek még nem szerepelnek benne. Tehát ({1,2,3}) | ({1,3,5}) eredménye ({1,2,3,5}). Megjegyzés: a elemeinek sorrendje megváltozhat.
Kizáró vagy (a ^ b)
A kizáró vagy, illetve szimmetrikus differencia eredménye azon elemek tömbje, melyek a-ban vagy b-ben vannak, de nem fordulnak elő mindkettőben egyszerre. Például ({1,3,5,6}) ^ ({4,5,6,7}) eredménye ({1,3,4,7}).
Felosztás, osztás (a / b)
Az osztás eredmény olyan tömbök tömbje, mely ha b szintén tömb, akkor a részeit b előfordulásainál felosztva tartalmazza, viszont ha b int vagy float, akkor minden b-edik elemnél osztja fel a-t. Tehát például {1,2,3,4,5}) / ({2,3}) eredménye ({ ({1}), ({4,5}) }), és {1,2,3,4}) / 2 eredménye ({ ({1,2}), ({3,4}) }).
Maradék, modulo (a % b)
Ez csak akkor érvényes, ha b integer, és ekkor azt a maradékot adja vissza, ami nem fordul elő a / b-ben.
Eredménye a ({ }) operátoréval megegyező, azaz a paraméterekből képzett tömbbel tér vissza. Tehát például ({1,2,3}) eredménye megegyezik az aggregate(1,2,3)-éval.
Lefoglal egy meret méretű tömböt, melynek elemei kezdetben mind 0-k.
1-el tér vissza, ha a paraméter tömb, 0-val különben.
E függvény végigmegy a elemein, mindegyiket ind-del indexeli, és az eredményből épített tömböt adja vissza. Tehát például column( ({ ({1,2,3}), ({4,5,6}), ({7,8,9}) }), 2) eredménye ({3,6,9}).
Két tömb méret- és tartalombeli egyezőségét vizsgálja (tehát nem kell azonos memóriacímen elhelyezkedniük).
A filter a azon elemeit adja vissza, melyre a func-ot első paraméterként az adott elemmel, a maradék paraméterbe pedig args-t helyettesítve az eredmény igaz.
A map a filter-hez hasonlóan működik, ám ez a func függvényt az előző módon meghívva, annak eredményeinek tömbjét adja vissza.
a-nak olyan másolatát készíti el, melyben minden mit elemet mire-re cserél.
Megfordítja a elemeinek sorrendjét.
E függvény működése a column-éhoz hasonló. a-t az indexek tömb elemeivel indexeli, és az eredmények tömbjét adja vissza. Például rows( ({"a","b","c"}), ({ 2,1,2,0}) ) eredménye ({"c","b","c","a"}).
Azzal az indexszel tér vissza, ahol a tu először előfordul a szenakazal-ban (egyenlőségvizsgálatnak ==-t használ).
A tomb tömb elemeinek számát adja vissza.
E függvény tomb-ot rendezi növekvő sorrendbe. Egész és lebegőpontos számok, valamint karakterláncok rendezésére is képes. Ha több paraméter is van, azok a tomb-hoz hasonlóan lesznek rendezve.
E függvény a-ból eltávolítja az azonos elemeket, azokból csak egy példányt hagyva meg. Az eredményben az elemek sorrendje bármilyen lehet.
asszociatív tároló (mapping)
Speciális tömbök, melyekben tetszőleges típusú indexeket használhatunk, akár minden adathoz különböző típusút. Így nincs sorrend az adatok között. A tömbnél lassabb, és több memóriát használ, de van hozzá egy lookup függvény, amely "gyorsan" keres az adatok között.
Pl:
Használható operátorok és függvények:
multihalmaz (multiset)
Hasonló a mappinghez, de nincsenek értékei, csak indexek. Indexeléskor igaz értéket kapunk vissza, ha van ilyen érték a halmazban, egyébként hamisat.
Értékadáskor (pl. mset [ ind ] = val), ha val=igaz, akkor az ind beletevődik a halmazba, ha nem igaz, akkor kiveszi belőle.
Pl:
program
A Pike a program elnevezést használja az osztályokra. A Pike program egy class leírása fileban. Ha egy file-ból olvasunk be egy forrást, akkor a szintaktika a következő:
Vagy cast-olással:
Vagy, ha az interpreteren belül akarunk programot írni, akkor használhatjuk a class kulcsszót:
Pl:
Az tagváltozók objektum-szintűek, tehát minden, az osztályból létrehozott objektumban külön szerepelnek. A create függvény speciális, ez felel meg a C++-beli konstruktornak. Habár a Pike-ban van szemétgyűjtő, de definiálhatunk destruktort. Ezt destroy-nak kell neveznünk.
Az adattagokra és metódusokra alkalmazható módosítók:
objektum
A program konkrét megvalósítása. A klónozás (cloning) művelettel foglalunk le a program számára memóriahelyet, és így készítünk belőle objektumot. Az objektum a program egy példánya. Ez hasonlóan történik, mint C++-ban:
vagy paraméterezve(például az állat súlya):
Az objektum metódusait és tagváltozóit a -> operátorral érhetjük el. pl: dog->weight.
Objektumokkal kapcsolatos függvények és operátorok:
Indexelés:
Az objektum karakterlánccal indexelhető, ily módon elérhetőek változói és függvényei. Ha változóról van szó, akár értéket is adhatunk neki ezzel a módszerrel. Függvény esetén az indexelés a rá mutató referenciát adja vissza, konstansoknak pedig az értékét. Megjegyzés: a -> operátor lényegében megegyezik az indexeléssel. Tehát az o->foo ugyanaz mint az o["foo"].
Klónozás:
Egy program klónozása kétféle módon történhet, vagy egy programra mutató referenciát függvényként meghívja, vagy pedig a new() illetve clone() függvények segítségével.
Egy objektum klónozásakor először a globális változók inicializálása történik meg, és utána meghívódik a create függvény a program argumentumaival paraméterezve.
void destruct(objektum o)
E függvény érvénytelenít minden, a paraméterbeli o objektumra mutató referenciát, valamint felszabadítja az objektum minden változóját. Ez a függvény hívódik meg akkor is, ha az objektumra mutató összes hivatkozás megszűnik. Ha van az objektumnak destroy függvénye, az végrehajtódik az objektum megszüntetése előtt.
program objektum_program(objektum o)
Visszatér a programmal, melyből a paraméterbeli o objektumot klónozták.
int objektump(mixed o)
1-el tér vissza, ha a paraméterbeli o objektum, 0-val különben. Ha az o objektum már megszűnt, a függvény 0-val tér vissza.
objektum this_objektum()
E függvény azzal az objektummal tér vissza, amelyet az interpreter éppen végrehajt.
array values(objektum o)
E függvény visszatérési értéke megegyezik a rows(o,indices(o))-éval, ami az o objektumban lévő azonosítók értékével tér vissza.
Összehasonlítás
Mint minden egyéb adattípusnál, itt is az == és a != használható két objektum egyenlőségének vizsgálatára.
Ahhoz, hogy megkönnyítsük a Pike-ban való progrmozást és hogy rövidebbé tegyük a kódot, néhány függvény meghívható a kódban 1-2 karakter leírásával. Ezeket a függvényeket operátoroknak hívjuk, és láthattuk már rengeteg példában hogyan is működnek. Ebben a fejezetben részletesen leírjuk mit is csinálnak. Az operátorokat kategóriákba soroljuk az alapján, hogy mire szolgálnak, de néhány operátornak olyan jelentése van, ami túlmegy a kategóriája hatáskörén.
Az aritmetikai operátorok a legegyszeűbbek, mivel úgy működnek, ahogy azt matematikában tanultuk. Ezek az aritmetikai operátorok:
Funkció | Szintaxis | Azonosító | Jelentés |
Összeadás | a + b |
`+ |
a és b összege |
Kivonás | a - b |
`- |
a és b különbsége |
Negáció | - a |
`- |
(-1) * a |
Szorzás | a * b |
`* |
a szorozva b-vel |
Osztás | a / b |
`/ |
a osztva b-vel |
Maradékolás | a % b |
`% |
a maradéka a/b-nek |
A harmadik oszlop, "Azonosító" a neve a függvénynek ami elvégzi a műveletet. Például a + b szintén írható +(a, b) alakban. A fejezet végén megmutatjuk, hogy milyen hasznos dolog is ez.
Mikor ezeket egész vagy valós számokra alkalmazzuk, akkor pontosan azt teszik, amit jelentenek. Egyedül a Maradékoló operátort nem ismerjük az általános matematikából. A maradékoló utasítás a maradékot adja vissza egy egész osztásból. Ez ugyanaz, mint az a - floor(a / b) * b. floor lekerekíti az értéket a legközelebbi kisebb vagy egyenlő egészre. Vegyük észre, hogy a floor hívása nem szükséges, ha egészekkel dolgozunk, mivel két egész hányadosa egész szám, ami a lekerekített érték. Például 8 / 3 értéke 2.
Ha minden argumentuma az operátornak egész, akkor az eredmény is egész lesz. Ha az egyik valós, a másik egész, akkor az eredmény valós értékű lesz. Ha mindkettő valós, akkor természetesen az eredmény is valós.
A Pike-ban több típus van, nem csak az egész és a valós, így itt a komplett lista a típusok kombinációjáról, amiket ezekkel az operátorokkal használhatunk:
Művelet | Visszaadott típus | Visszaadott érték |
|
int | a két érték összege |
|
float | a két érték összege |
|
string | Ebben az esetben a szám stringgé konvertálódik, majd a két string összefűződik egy új stringgé, amely visszaadódik. |
|
array | A két array konkatenálódik egy új tömbként, mely visszaadódik. |
|
mapping | Egy mapping adódik vissza az összes index-érték párral a két mappingból. Ha egy index mindkét mappingben szerepel, akkor a jobboldali mappingben lévő érték kerül az eredménybe. |
|
multiset | Egy multiset lesz az eredmény az összes indexszel mindkét multisetből. |
|
int | A jobboldali és a baloldali érték különbsége. |
|
float | A jobboldali és a baloldali érték különbsége. |
|
string | A baloldali string másolata a jobboldali string összes előfordulása nélkül. |
|
array | A baloldali tömb a jobb tömb béli értékek nélkül.
Például:({2,1,4,5,3,6,7}) - ({3,5,1})
= ({2,4,6,7}) . |
|
mapping | Egy új mapping az összes baloldali mapping index-érték párjával, kivéve azokat az indexeket, amelyek a jobboldaliban előfordulnak. |
|
multiset | A baloldali multiset értékei, kivéve amelyek előfordulnak a jobboldaliban. |
|
int | Ugyanaz mint 0 - int . |
|
float | Ugyanaz mint 0 - float . |
|
int | A két érték szorzata |
|
float | A két érték szorzata |
|
string | A stringek a tömbben összefűződnek úgy, hogy minden elem közé a jobboldali string kerül. Példa: ({"foo","bar"})*"-" = "foo-bar" . |
|
array | Minden tömb a baloldali tömbből konkatenálódik úgy, hogy minden tömb közé a jobboldali tömb kerül.
Példa: ({ ({"foo"}) ,({"bar"})})*({"-"})
= ({ "foo","-","bar" }) . |
|
string | A stringet N-szer egymás után fűzi.
Példa: "foo"*3 = "foofoofoo" . |
|
string | A stringet X-szer egymás után fűzi.
Példa: "foo"*2.5 =
"foofoofo" . |
|
string | A tömböt N-szer összefűzi.
Példa:({"foo"})*3
= ({"foo","foo","foo"}) . |
|
string | A tömböt X-szer összefűzi.
Példa: ({1,2,3})*2.5 = ({1,2,3,1,2,3,1,2}) . |
|
int | A bal- és a jobboldali érték hányadosának alsó egészrésze. |
|
float | A bal- és jobboldali érték hányadosa. |
|
array(string) | Szimmetrikusan a szorzás operátorral, az osztás feldarabolja a stringet.
A jobboldali string előfordulásainál darabolódik fel a baloldali string.
Példa: "foo-bar"/"-" = ({"foo","bar"}) |
|
array(string) | A stringet N hosszúságú darabokra szedi, csak a teljes darabok lesznek az eredményben, a maradékot elhagyja.
Példa: "foo-bar"/2 = ({"fo","o-","ba"}) |
|
array(string) | Hasonló az egésszel osztáshoz, de megengedi a töredék méretű darabokat, és a maradékot is tartalmazza az eredmény.
Példa: "foo-bar"/2.5 visszatér ({"fo","o-b","ar"}) |
|
array(array) | Ugyanaz mint a string egésszel való osztása, csak tömbbel végzi a műveletet.
Példa: ({1,2,3,4,5,6,7})/2 = ({({1,2}),({3,4}),({5,6})}) |
|
array(array) | Ugyanaz mint a string float-tal való osztása, csak tömbbel végzi a műveletet.
Példa:({1,2,3,4,5,6,7,8})/2 =
({({1,2}),({3,4,5}),({6,7}),({8})}) |
|
int | Az osztás maradéka. Ha a és b egészek, akkor a%b ugyanaz, minta-(a/b)*b. |
|
float | Az osztás maradéka. Ha a és b egészek, akkor a%b ugyanaz, mint a-floor(a/b)*b |
|
string | A maradéka egy string osztásnak. Példa:
"foo-bar"%2 = "r" |
|
string | A maradéka egy array osztásának. Példa:
({1,2,3,4,5,6,7})%2 = ({7}) |
Az aritmetika operátorok használata nehéz lenne anélkül, hogy összehasonlíthatnánk az eredményeket egymással. Erre a célra 6 operátor van:
Funkció | Szintaxis | Azonosító | Visszaadott érték |
Ugyanaz | a == b |
`== |
1 ha a értéke ugyanaz mint b, 0 különben |
Nem ugyanaz | a != b |
`!= |
0 ha a értéke ugyanaz mint b, 1 különben |
Nagyobb | a > b |
`> |
1 ha a nagyobb mint b, 0 különben |
Nagyobb vagy egyenlő | a >= b |
`>= |
1 ha a nagyobb vagy egyenlő mint b, 0 különben |
Kisebb | a < b |
`< |
1 ha a kisebb mint b, 0 különben |
Kisebb vagy egyenlő | a <= b |
`<= |
1 ha a kisebb vagy egyenlő b, 0 különben |
Az == és != operátorok bármely típussal használhatóak. Ahhoz, hogy 2 érték megegyezzen, ugyanolyan típusúnak kell lenniük, tehát 1 és 1.0 az nem ugyanaz. Szintén, hogy két pointer megegyezzen, a két értéknek ugyanarra az objektumra kell mutatni, az nem elég, hogy a két objektum ugyanolyan méretű és ugyanaz a tartalma.
A többi operátort a táblában csak integerekkel, floatokkal és stringekkel használhatjuk. Ha összehasonlítunk egy integer-t egy float-tal, akkor az integer float-tá konvertálódik az összehasonlítás előtt. Ha stringeket hasonlítunk, akkor a lexikai sorrend számít a LC_CTYPE és LC_LANG környezeti változóknak megfelelően.
A logika operátorok azok, amelyek az igaz értékekkel operálnak. Pike-ban minden érték, kivéve a nulla, igaz érték. A logikai operátorok alapvető részei a Pike-nak. Ezek el tudják még dönteni azt is, hogy melyik argumentum értékelődjön ki és melyik ne. Mivel logikai operátoroknak nincs azonosítójuk, így függvényként sem lehet meghívni őket. Négy logikai operátor van:
Funkció | Szintaxis | Visszatérési érték |
És | a && b |
Ha a hamis, a adódik vissza és b nem lesz kiérékelve, különben b adódik vissza. |
Vagy | a || b |
Ha a igaz, akkor a adódik vissza és b nem kerül kiértékelésre, különben b adódik vissza. |
Nem | ! a |
0 ha a igaz, 1 különben. |
Ha-különben | a ? b : c |
Ha a igaz, b adódik vissza és c nem értékelődik ki, különben c adódik vissza és b nem értékelődik ki. |
Ezek az operátorok bitek állítgatására használhatóak mint halmazok elemei. Szintén használhatóak tömbökre, mapping-ekre és halmazokra.
Funkció | Szintaxis | Azonosító | Visszatérési érték |
Léptetés balra | a << b |
`<< |
Megszorozza a-t 2b-vel. |
Léptetés jobbra | a >> b |
`>> |
Osztja a-t 2b -vel. |
Inverz (nem) | ~ a |
`~ |
-1-a |
Metszet (és) | a & b |
`& |
Minden elem, ami van a-ban és b-ben is.. |
Unió (vagy) | a | b |
`| |
Minden elem, ami vagy a-ban vagy b-ben van. |
Szimmetrikus különbség (kizáró vagy) | a ^ b |
`^ |
Minden elem, ami vagy a-ban vagy b-ben van, de nincs mindkettőben. |
Az első három operátor csak integer-ekre alkalmazható nyilvánvalóan.
A másik három, a metszet, unió és szimmetrikus különbség alkalmazható integer-ekre, array-okra, multiset-ekre és mapping-ekre. Ha integer-ekkel használjuk, akkor minden bit a számban külön elemként szerepel.
Ha a metszetet, uniót és szimmetrikus különbséget array-el használjuk, akkor minden elem az array-ban önmagaként kezelődik. Tehát ha metszetét vesszük két array-nak, akkor az eredmény egy másik array lesz, mely tartalmazza azokat elemeket, mely mindkét arrayban megtalálhatóak. Pl.:({7,6,4,3,2,1}) & ({1, 23, 5, 4, 7}) = ({7,4,1}). Az elemek sorrendje a visszaadott array-ban mindig a baloldali array szerint lesz. Multiset-ek elemei ugyanúgy kezelődnek mint az array elemei. Ha mappingon végzünk műveletet, csak az indexek számítanak. Az értékek csak az indexekkel együtt másolódnak. Ha egy index a halmazművelet mindkét argumentumában megtalálható, akkor a jobboldali értéke fog számítani. Pl.: ([1:2]) | ([1:3]) = ([1:3]).
Az index és az intervallum operátorokat komplex adatszerkezetekből információ kinyerésére használjuk.
Funkció | Szintaxis | Azonosító | Visszatérési érék |
Index | a [ b ] |
`[] |
Visszaadja a b indexű elemét. |
Lookup | a ->identifier |
`-> |
Megkeresi az azonosítót. Ugyanaz mint a["identifier"]. |
Index hozzárendelés | a [ b ] = c |
`[]=; |
A b indexű elem értékét c-re állítja. |
Index hozzárendelés | a ->identifier
= c |
`->= |
Az "identifier" indexű elem értékét c-re állítja. |
Intervallum | a [ b .. c ] |
`[..] |
Visszaadja az a szeletét b-től c indexig. |
Intervallum | a [ .. c ] |
`[..] |
Visszaadja az a szeletét az a elejétől b indexig. |
Intervallum | a [ b .. ] |
`[..] |
Visszaadja az a szeletét b indextől az a végéig |
Az index operátort kétféleképpen írhatjuk le. Írhatjuk ob[ index ] vagy ob->identifier alakban, mivel az utóbbi ekvivalens az ob[ "identifier" ] alakkal.
Csak string, array, mapping, multiset és object indexelhető, és ezek különbözőképpen indexelhetőek, melyet a következő táblázat mutat:
Művelet | Eredmény |
|
Visszaadja az ascii értékét az N-edik karakternek a stringben. |
|
Visszaadja az N-edik elemét az array-nak. |
|
Beállítja az N-edik elem értékét az array-ban a mixed értékre. |
|
Visszaadja az értéket az adott indexről, 0 ha nincss ilyen index. |
|
Az első mixed elem értéke a második mixed értéke lesz. |
|
1-et ad vissza, ha az index (a zárójelben lévő érték) bennevan a multiset-ben, különben 0 az eredmény. |
|
Ha a mixed érték igaz, akkor az index hozzáadódik a multisethez, különben az index kivevődik a multisetből. |
|
Visszaadja az azonosítóhoz tartozó értéket az objektumban. |
|
Beállítja az objektumbeli azonosítóhoz tartozó értéket az adott mixed-re. Csak akkor működik, ha az azonosító referencia egy változóra az objektumban. |
|
Visszaadja a névkonstans értékét a programból. |
|
Visszaadja a string részstringjét. |
|
Visszaadja az array egy szeletét. |
Ha array-t vagy string-et indexelünk, akkor néha kényelmesebb a végéről indexelni, mint az elejéről. Ezt a funkciót könnyen használhatjuk, ha negatív indexeket használunk, az arr[-i] az ugyanaz, mint arr[sizeof(arr)-i]. Fontos megjegyezni, hogy ez nem igaz az intervallumokra, ehelyett a intervallum(range) operátor szorítja meg az argumentumokat a megfelelő értékekre. Ez azt jelenti, hogy a[b..c] a következőt eredményezi:
Igazából csak egyetlen értékadó operátor van, de kombinálható sok másik operátorral, ami a kódot rövidebbé teszi. Egy értékadás így néz ki:
A változó lehet lokális változó, globális változó vagy egy indexe egy array-nak, objektumnak vagy mapping-nek. Természetesen ez a változóban tárolt értéket kifejezésre fogja változtatni. Jegyezzük meg, hogy a fenti példa szintén egy kifejezés, melynek értéke a kifejezés. Ezt érdekes módokon használhatjuk fel:
Az értékadás ilyen használata megtévesztheti a kezdő felhasználókat, vagy azokat akiknek Pascal vagy Basic hátterük van. Különösen az if utasítást keverhetik az if(variable == expression) alakkal, ami egy teljesen más dolgot jelent. Ahogy előzőekben már említettük az értékadó operátor más operátorokkal kombinálható, mely egy olyan operátort képez, amely nem csak simán értéket ad a változónak, hanem módosítja a tartalmát. Itt a teljes lista ezekről a kombinációkról:
Szintaxis | Ugyanaz mint: | Funkció |
változó += kifejezés |
változó = változó + kifejezés | Add a kifejezés-t a változó-hoz |
változó -= kifejezés |
változó = változó - kifejezés | változó-ból vond ki a kifejezés-t |
változó *= kifejezés |
változó = változó * kifejezés | Szorozd meg a változó kifejezéssel |
változó /= kifejezés |
változó = változó / kifejezés | Oszd el változó-t kifejezéssel |
változó %= kifejezés |
változó = változó % kifejezés | Maradékold a változót kifejezéssel |
változó <<=
kifejezés |
változó = változó << kifejezés | Told el változó bitjeit kifejezéssel balra |
változó >>=
kifejezés |
változó = változó >> kifejezés | Told el változó bitjeit kifejezéssel jobbra |
változó |= kifejezés |
változó = változó | kifejezés | változó-t VAGY-old a kifejezéssel |
változó &=
kifejezés |
változó = változó & kifejezés | változó-t ÉS-eld kifejezéssel |
változó ^= kifejezés |
változó = változó ^ kifejezés | változó XOR-old kifejezéssel |
Ezekben a kifejezésekben a változó bármilyen típusú lehet, aminek lehet értéket adni. Ezeket balértékként ismerjük. Ezek a balértékek:
Balérték típus | Szintaxis | Érvényes értékadás |
lokális vagy globális változó | azonosító | ugyanaz, mint a változó |
array egy eleme | array [ int ] | bármilyen típus |
elements in elements in an array | array [ string ] | any type This is like map(arr, `[]=,string_indexing_element, assignment_element) |
egy elem a stringben | string [ int ] | integer |
egy elem egy mapping-ban | mapping[mixed] or mapping->identifier | bármilyen típus |
egy elem egy multiset-ben | multiset[mixed] or multiset->identifier | igaz / hamis |
változó egy objektumban | object[string] or object->identifier | ugyanaz a típus mint a változó |
balértékek listája | [ lvalue, lvalue ] | egy tömb, első elemnek a tömbben az első érték, a másodiknak a második érték adódik értékül (és így tovább). |
Már csak néhány operátor maradt hátra. Ezeket most ebben a csoportban mutatjuk be, nem azért mert nem fontosak, csak nem illenek bele egyik másik csoportba sem.
Funkció | Szintaxis | Azonosító | Visszatérési érték |
Hívás |
a ( args ) | `() | Meghívja az a függvényt. |
splice | @ a | nincs |
A tömb minden egyes elemével meghívja a függvényt. |
Növelés |
++ a | nincs |
Növeli a-t és visszaadja az új értékét. |
Csökkentés |
-- a | nincs | Csökkenti a-t és visszaadja az új értékét. |
Utólagos növelés | a ++ | nincs | Növeli a-t és visszaadja az régi értékét. |
Utólagos csökkentés | a -- | nincs | Csökkenti a-t és visszaadja az régi értékét. |
casting |
(type) a | nincs | Megpróbálja a értékét type típusra alakítani. |
a, b | nincs | Kiértékeli a-t és b-t, majd visszaadja b-t. |
A legfontosabb ezen operátorok közül a hívás operátor. Az operátor maga csak egy pár zárójel a kifejezés után írva megadja a függvényt. Az argumentumokat a zárójelek között kell megadni vesszővel elválasztva. Már láthattunk sok példát erre az operátorra, bár akkor még nem tudhattuk, hogy ez egy operátor. A függvényhívás operátor többet tud, mint szimplán meghív egy függvényt: a "függvény" lehet egy tömb, az operátor pedig ezen a tömbön végighaladva meghív sorban minden egyes elemet, és visszaad egy tömböt az eredményekkel.
Másrészről a "függvény" egy program, az operátor klónoz egy objektumot a programból és meghívja a create() metódust az új objektumban az adott argumentumokkal. Tehát a clone így van implementálva:
A függvényhívásoknál meg kell említeni a splice operátort is. A splice operátor egy kukac a kifejezés előtt. A kifejezés mindig egy tömb. A splice operátor a tömb minden egyes elemét külön átadja a függvényhívásnak. Az operátort csak argumentum listában, függvényhívásnál használhatjuk.
Itt vannak a növelő és csökkentő operátorok. Ezek valamelyest korlátozottak: csak integer-eken lehet használni őket. Gyorsan és egyszerűen használhatóak az 1 kivonására és hozzáadására egy integerhez. Ha az operátor a változó előtt van (++a), a visszaadott érték a változó a művelet előtti értéke lesz, ha a változó után van írva, akkor a művelet utáni érték adódik vissza.
A casting-ot az egyik típus másik típussá konvertálásakor alkalmazzuk, de nem minden konverzió lehetséges. A lehetséges konverziók, amik csinálnak valamit:
konvertálás erről | erre |
művelet |
int | string | Átkonvertálja az int-et az ASCII reprezentációjára. |
float | string | Átkonvertálja az float-ot az ASCII reprezentációjára. |
string | int | Átkonvertálja a decimális, oktális vagy hexadecimális számot egy int-té. A jövőbeni verziókban csak a decimális konverzió fog működni. |
string | float | Az ASCII számot float-tá konvertálja. |
string | program | A string egy filenév, a program lefordul és a program visszaadódik. Az eredmény cache-elődik. |
string | object | Először konvertája a stringet programmá, (lásd előbb), majd klónozza az eredményt. Az eredmény cache-elődik. |
object | type | Meghívja a 'cast' függvényt egy stringgel, melynek tartalma a type. |
string | array | Ugyanaz mint values(string). |
array(int) | string | Ez az ellenkezőjét csinálja az előzőnek, tehát ez egy stringet készít egy integer array-ból. |
array | array(type) | Rekurzívan konvertálja a tömb összes elemét |
mapping | array | Ugyanaz mint Array.transpose(({indices(mapping),values(
mapping)) .Pl.: (array)([1:2,3:4]) = ({
({1,2}), ({3,4}) }) |
multiset | array | Ugyanaz mint indices(multiset) . |
int | float | int értékű float-ot ad vissza. |
float | int | A float-hoz legközelebbi integer-t adja vissza. |
function | object | Ugyanaz mint function_object(function) . |
A cast operátor használhatjuk még arra is, hogy a fordítónak megmondjunk dolgokat. Ha a egy mixed típusú változó int típusú értékkel, akkor az (int)a használható az a kifejezés helyett hogy a fordítóval közöljük, hogy a kifejezés értéke int.
És utoljára, de nem utolsó sorban a vessző operátor. Ez nem sok mindent csinál, szimplán kiértékeli a két argumentumát, majd visszaadja a jobboldali értékét. Ez az operátor legfőképpen arra szolgál, hogy rövidebb kódot írhassunk.
Ha egy kifejezést értékeltetünk ki, akkor mindig használhatunk zárójelet, hogy megmondjuk a fordítónak milyen sorrendben történjen. Alapesetben a fordító balról jobbra halad, de a magasabb precedenciájúakat előbb végzi el, mint az alacsonyabbakat. A következő táblázat a operátorok precedenciáját sorolja fel csökkenő sorrendben:
(a) a() a[b] a->b
a[b..c] ({}) ([]) (<>) |
!a ~a (type)a ++a --a |
a++ a-- |
a*b a/b a%b |
a+b a-b |
a>>b a<<b |
a>b a>=b a<b
a<=b |
a==b a!=b |
a&b |
a^b |
a|b |
&& |
|| |
a?b:c |
= |
@a |
, |
Példák:
Kifejezés |
a sorrend, ahogy kiértékelődik: |
1+2*2 |
1+(2*2) |
1+2*2*4 |
1+((2*2)*4) |
(1+2)*2*4 |
((1+2)*2)*4 |
1+4,c=2|3+5 |
(1+4),(c=((2|3)+5)) |
1+5 & 4 == 3 |
(1+(5 & 4)) == 3 |
c=1,99 |
(c=1),99 |
!a++ + ~--a() |
(!(a++)) + (~((--a)())) |
Ahogy korábban említettük a + b írható `+(a, b) alakban is. Együtt a map függvénnyel, mely meghív egy függvényt minden indexére egy array-nek, és a splice operátorral nagyon-nagyon gyors és kompakt kódot írhatunk. Nézzünk néhány példát:
Ez egy tömböt eredményez, ahol minden elem az eredeti negáltja lesz.
Ez a szöveget sorokra bontja, minden sor szavak listájára osztja a `/ -vel.
Ez az összes integert összeadja az arr array-ben.
Ez egy kicsit abszurd, de működő függvény, ami az a abszolútértékét adja vissza.