A Zig egy imperatív, általános célú, statikusan tipizált, fordított rendszerprogramozási nyelv, amelyet Andrew Kelley tervezett. A C nyelv utódjának szánják, azzal a szándékkal, hogy még kisebb és egyszerűbb legyen a programozás, ugyanakkor több funkciót kínáljon. A Zig szabad és nyílt forráskódú szoftver, amelyet MIT licenc alatt adnak ki.
A nyelv egyszerűségét érintő fejlesztések a folyamatkezelésre, a függvényhívásokra, a könyvtárimportra, a változók deklarálására és a Unicode támogatásra vonatkoznak. A nyelv nem használ makrókat vagy preprocesszor utasításokat. A modern nyelvekből átvett funkciók közé tartozik a fordítási idejű általános típusok hozzáadása, amelyek lehetővé teszik, hogy a függvények különböző adatokkal dolgozzanak, valamint egy kis számú új fordítói utasítás, amely lehetővé teszi a típusokra vonatkozó információk elérését a tükrözésAz informatikában a reflektív programozás vagy reflexió egy folyamat azon képessége, hogy saját struktúráját és viselkedését megvizsgálja, "magába nézzen", és módosítsa. segítségével.
A Zig egy másik kiegészítése a kódbiztonságot hivatott javítani. A C-hez hasonlóan a Zig nem tartalmaz szemétgyűjtést (garbage collection), és a memóriakezelés manuális. Az ilyen rendszerekben felmerülő potenciális hibák kiküszöbölése érdekében tartalmaz opciós típusokat és egyszerű szintaxist a használatukhoz. A nyelvbe egy tesztelési keretrendszer is beépítésre került.
Leírás Célok A Zig elsődleges célja, hogy jobb megoldást kínáljon a jelenleg C-vel megoldott feladatokra. Ebben a tekintetben elsődleges szempont az olvashatóság; a Zig megpróbálja a meglévő fogalmakat és szintaxist használni, ahol csak lehetséges, elkerülve a hasonló fogalmak eltérő szintaxisának hozzáadását. Továbbá a „robusztusság, optimalizálás és karbantarthatóság” érdekében tervezték, számos olyan funkciót tartalmaz, amelyek javítják a biztonságot, az optimalizálást és a tesztelést. A kis és egyszerű szintaxis fontos része a karbantartásnak, mivel a nyelv célja, hogy a karbantartók anélkül tudják hibakeresni a kódot, hogy meg kellene tanulniuk egy olyan nyelv bonyolultságát, amelyet esetleg nem ismernek. A Zig még ezekkel a változtatásokkal együtt is képes a meglévő C kódba és a meglévő C kóddal szemben fordítani; a C fejléceket („header”) be lehet építeni egy Zig projektbe, azok függvényeit meg lehet hívni, és a Zig kódot a fordító által készített fejlécek beépítésével be lehet linkelni a C projektekbe.
A kód egyszerű és könnyen olvashatóvá tételének általános tervezési filozófiájával összhangban a Zig rendszer egésze számos stilisztikai változást is tartalmaz a C-hez és más C-szerű nyelvekhez képest. A Rust nyelv például rendelkezik operátor-túlterhelésselA számítógépes programozásban az operator overloading, amelyet néha operátor ad hoc polimorfizmusnak is neveznek, a polimorfizmus egy speciális esete, ahol a különböző operátorok argumentumaiktól függően különböző implementációkkal rendelkeznek., ami azt jelenti, hogy az a = b + c típusú utasítás valójában a plus operátor egy típushoz tartozó, túlterhelt változatának függvényhívása lehet. Továbbá, ez a függvény pánikba eshet, ami megelőzheti a következő kódot. A Zig-ben, ha valami meghív egy függvényt, akkor az függvényhívásnak tűnik, ha nem, akkor nem függvénynek. Ha hibát vet fel, az explicit a szintaxisban a hibakezelés hibatípusokon keresztül történik, és catch vagy try segítségével kezelhető.C++ try-catch példa:// Example in C++ try { // Code that may throw an exception int result = 10 / 0; // Division by zero 💥 } catch (const std::exception& ex) { // Handling the exception std::cout << "Error: " << ex.what() << std::endl; }
A Zig céljai ellentétben állnak sok más, ugyanebben az időszakban tervezett nyelvvel, mint például a Rust, a Carbon és a Nim. Ezek a nyelvek általában összetettebbek, olyan kiegészítő funkciókkal, mint az operator overloading, az értékeknek (tulajdonságoknak) álcázott függvények és sok más, a nagyméretű programok felépítését segíteni hivatott funkció. Ezek a fajta funkciók inkább a C++ megközelítésével közösek, és ezek a nyelvek inkább annak a nyelvnek a vonalait követik. A Zig a típusrendszer konzervatívabb kiterjesztése, amely támogatja a fordítási idejű generikusokat, és a comptime direktívával a „kacsatipizálás” egy formáját alkalmazza.
A memória kezelése A C programokban a hibák egyik elsődleges forrása a memóriakezelő rendszer, amelynek alapja a malloc. A malloc egy memóriablokkot különít el a kódban való használatra, és egy hivatkozást ad vissza erre a memóriára mutató formájában (pointer). Nincs olyan rendszer, amely biztosítaná, hogy a memória felszabaduljon, amikor a programnak már nincs rá szüksége, ami ahhoz vezethet, hogy a programok az összes rendelkezésre álló memóriát felhasználják, ami memóriaszivárgást jelent. Gyakoribb a lógó mutatóA számítógépes programozásban a lógó mutatók (dangling pointer és wild pointer) olyan mutatók, amelyek nem a megfelelő típusú, érvényes objektumra mutatnak., amely nem megfelelően kiosztott memóriaobjektumra hivatkozik.
Ezekre a problémákra gyakori megoldás a szemétgyűjtő (GC), amely megvizsgálja a programot a korábban betöltött memóriára mutató mutatók után, és eltávolítja azokat a blokkokat, amelyekre már nem mutat semmi. Bár ez nagymértékben csökkenti, vagy akár meg is szünteti a memóriahibákat, a GC rendszerek viszonylag lassúak a kézi (utasítással előírt) memóriakezeléshez képest, és kiszámíthatatlan a teljesítményük, ami alkalmatlanná teszi őket a rendszerprogramozásra. Egy másik megoldás az automatikus referenciaszámlálás (ARC),Az Automatic Reference Counting (ARC) a Clang fordító memóriakezelési funkciója, amely automatikus referenciaszámlálást biztosít az Objective-C és a Swift programozási nyelvek számára. amely ugyanazt az alapkoncepciót valósítja meg a használaton kívüli memóriablokkok azonosítására, de ezt a mutató létrehozásakor és megsemmisítésekor az adott blokkra mutató mutatók számának rögzítésével teszi, ami azt jelenti, hogy nincs szükség kimerítő mutatókeresésre, hanem minden malloc (allokálás) és release (felszabadítás) művelethez hozzáadódik a referenciaszámláló beállításának többletköltsége.
A Zig célja, hogy a C-hez hasonló vagy annál jobb teljesítményt nyújtson, ezért a GC és az ARC nem megfelelő megoldások. Ehelyett egy modern, 2022-től kezdődő koncepciót használ, az úgynevezett opciós típusokat.A programozási nyelvekben (különösen a funkcionális programozási nyelvekben) és a típuselméletben az opciós típus (option type vagy maybe type) egy olyan polimorf típus, amely egy opcionális érték kapszulázását jelenti. Ahelyett, hogy egy mutató a semmire vagy nil-re mutathatna, egy külön típust használunk az opcionálisan üres adatok jelölésére. Ez hasonló ahhoz, mintha egy struktúrát használnánk egy mutatóval és egy boolean értékkel, amely jelzi, hogy a mutató érvényes-e, de a boolean állapotát a nyelv láthatatlanul kezeli, és nem kell a programozónak explicit módon kezelnie. Így például a mutató deklarálásakor „nem allokált” állapotba kerül, és amikor ez a mutató értéket kap egy malloc-tól, akkor „allokált” állapotba kerül, ha a malloc sikeres volt.
Ennek a modellnek az az előnye, hogy nagyon alacsony vagy nulla overheaddelAz informatikában az overhead a többlet vagy közvetett számítási idő, memória, sávszélesség vagy más erőforrások bármilyen kombinációja, amelyek egy adott feladat végrehajtásához szükségesek. jár; a fordítónak kell létrehoznia a kódot, hogy a mutatók manipulálásakor továbbadja az opcionális típust, szemben egy egyszerű mutatóval, de ez lehetővé teszi, hogy közvetlenül kifejezze az esetleges memóriaproblémákat fordítási időben, futásidejű támogatás nélkül. Például egy null értékű mutató létrehozása, majd annak felhasználási kísérlete tökéletesen elfogadható C-ben, ami nullmutató hibához vezet (null pointer assignment).A számítástechnikában a null pointer (néha nullptr-nek vagy nullnak rövidítve) vagy null reference egy olyan érték, amelyet annak jelzésére tárolnak, hogy a mutató vagy hivatkozás nem érvényes objektumra hivatkozik. Ezzel szemben egy opcionális típusokat használó nyelv ellenőrizni tudja, hogy minden kódút csak akkor próbálja meg használni a mutatókat, ha azok érvényesek. Ez ugyan nem küszöböli ki az összes lehetséges problémát, de ha futásidőben problémák merülnek fel, a hiba pontosabban lokalizálható és megmagyarázható.
Egy másik változás a memóriakezelésben a Zigben az, hogy a tényleges kiosztás a műveletet leíró struktúrákon (struct) keresztül történik, szemben a libcA C standard library vagy libc a C programozási nyelv szabványos könyvtára, az ISO C szabványban meghatározottak szerint. memóriakezelő függvényeinek meghívásával. Például, ha C nyelven olyan függvényt akarunk írni, amely egy másik karakterlánc többszörös másolatát tartalmazó karakterláncot készít, a függvény így nézhet ki: const Allocator = std.mem.Allocator;
const char* repeat(const char* original, size_t times);
A kódban a függvény megvizsgálná az original méretét, majd a times malloc-méretét, hogy memóriát különítsen el a felépítendő karakterlánc számára. Ez a malloc láthatatlan az azt hívó függvények számára, ha nem sikerül később felszabadítani a memóriát, szivárgás lép fel. A Zig-ben ezt egy olyan függvénnyel lehetne kezelni, mint a következő: fn repeat(allocator: std.mem.Allocator, original: []const u8, times: usize) std.mem.Allocator.Error![]const u8;
Ebben a kódban az allocator változónak átadunk egy struktúrát, amely leírja, hogy milyen kódnak kell végrehajtania az allokációt, és a repeat függvény vagy az eredményül kapott karakterláncot adja vissza, vagy az opcionális típus használatával, amint azt a ! jelzi, egy Allocator.Error. Azáltal, hogy az allokátor közvetlenül bemenetként van kifejezve, a memória kiosztása soha nem „rejtőzik” egy másik függvényen belül, hanem mindig az a függvény teszi hozzáférhetővé az API számára, amely végül a memória kiosztását kéri. A Zig szabványos könyvtárán belül nem történik allokálás. Továbbá, mivel a struktúra bármire mutathat, használhatunk alternatív allokátorokat, akár a programban írtakat is. Ez lehetővé teheti például olyan kis objektum-allokátorok használatát, amelyek nem használják az operációs rendszer azon függvényeit, amelyek általában egy teljes memóriaoldaltA memory page a memória fix hosszúságú összefüggő (nem szegmentált) blokkja. allokálnak.
Az opcionális típusok egy olyan nyelvi jellemző példája, amely általános funkcionalitást kínál, miközben egyszerű és általános. Nem feltétlenül a nullmutatós problémák megoldására kell használni őket, hanem minden olyan értéktípusnál hasznosak, ahol a „nincs érték” megfelelő válasz. Tekintsünk egy countTheNumberOfUsers függvényt, amely egy egész számot ad vissza, és egy egész szám változót, theCountedUsers-t, amely az eredményt tartalmazza. Sok nyelvben a theCountedUsers változóba egy bűvös számot helyeznének el, hogy jelezzék, hogy a countTheNumberOfUsers még nem került meghívásra, míg sok implementáció egyszerűen nullára állítja azt. A Zig-ben ez úgy valósítható meg, hogy var theCountedUsers: ?i32 = null, ami a változót egyértelműen „nem hívták meg” értékre állítja.
A Zig egy másik általánosabb funkciója, amely szintén segít a memóriaproblémák kezelésében, a defer fogalma, amely bizonyos kódokat jelöl meg, amelyeket a függvény végén kell végrehajtani, függetlenül attól, hogy mi történik, beleértve az esetleges futásidejű hibákat is. Ha egy adott függvény memóriát foglal, majd a művelet befejeztével el is távolítja azt, akkor hozzáadhatunk egy sort, hogy elhalasszunk egy free-t, hogy biztosítsuk, hogy az felszabaduljon, bármi történjen is.
A Zig memóriakezelés elkerüli a rejtett allokációkat. A kiosztás nem közvetlenül a nyelvben történik. Ehelyett a halomhoz való hozzáférés egy szabványos könyvtárban történik, explicit módon.
Közvetlen interakció a C-vel