जिग प्रोग्रामिंग भाषा


आदर्श प्रोग्रामिंग लैंग्वेज के अद्भुत लेख सब्जेक्टिव विज़न पर पहली टिप्पणी ज़िग प्रोग्रामिंग भाषा के संदर्भ में हुई। स्वाभाविक रूप से, यह दिलचस्प हो गया कि यह किस तरह की भाषा है, जो C ++, D और Rust का एक आला होने का दावा करता है। मैंने देखा - भाषा बहुत सुंदर और कुछ रोचक लगी। नीस सी-जैसे सिंटैक्स, त्रुटि से निपटने के लिए मूल दृष्टिकोण, अंतर्निहित कोरआउट्स। यह लेख कोड के उदाहरणों को चलाने के लिए अपने स्वयं के विचारों और छापों के साथ अंतःस्थापित आधिकारिक दस्तावेज का एक संक्षिप्त अवलोकन है।

शुरुआत हो रही है


कंपाइलर को स्थापित करना काफी सरल है, विंडोज के लिए- बस वितरण पैकेज को कुछ फ़ोल्डर में अनज़िप करें। हम एक ही फ़ोल्डर में एक hello.zig टेक्स्ट फ़ाइल बनाते हैं, वहां प्रलेखन से कोड डालें और इसे सहेजें। असेंबली कमांड द्वारा किया जाता है

zig build-exe hello.zig 

जिसके बाद उसी निर्देशिका में hello.exe दिखाई देता है।

असेंबली के अलावा, यूनिट टेस्टिंग मोड उपलब्ध है, इसके लिए कोड में टेस्ट ब्लॉक का उपयोग किया जाता है, और टेस्ट और असेंबली का लॉन्च कमांड द्वारा किया जाता है।

 zig test hello.zig 

पहली विषमताएँ


कंपाइलर विंडोज लाइन ब्रेक (\ r \ n) का समर्थन नहीं करता है। बेशक, प्रत्येक प्रणाली (विन, निक्स, मैक) में टूटने वाला बहुत ही तथ्य अपने स्वयं के कुछ जंगलीपन और अतीत का अवशेष है। लेकिन ऐसा करने के लिए कुछ भी नहीं है, इसलिए बस चयन करें, उदाहरण के लिए, नोटपैड ++ में जो प्रारूप आप संकलक के लिए चाहते हैं।

दूसरी विषमता जो मुझे दुर्घटना से हुई - टैब कोड में समर्थित नहीं हैं! केवल रिक्त स्थान। लेकिन ऐसा होता है :)

हालांकि, यह ईमानदारी से प्रलेखन में लिखा गया है - सच्चाई पहले से ही बहुत अंत में है।

टिप्पणियाँ


एक और विषमता यह है कि जिग मल्टी-लाइन टिप्पणियों का समर्थन नहीं करता है। मुझे याद है कि प्राचीन टर्बो पास्कल - नेस्टेड मल्टी-लाइन टिप्पणियों में सब कुछ सही ढंग से किया गया था। जाहिर है, तब से किसी भी भाषा डेवलपर को इतनी सरल चीज़ में महारत हासिल नहीं है :)

लेकिन दस्तावेजी टिप्पणियां हैं। /// से शुरू करें। कुछ निश्चित स्थानों में होना चाहिए - संबंधित वस्तुओं (चर, फ़ंक्शन, कक्षाएं ...) के सामने। यदि वे कहीं और हैं - एक संकलन त्रुटि। बुरा नहीं है।

परिवर्तनीय घोषणा


अब फैशनेबल (और वैचारिक रूप से सही) शैली में किया जाता है, जब कीवर्ड (कॉन्स्ट या वर) पहले लिखा जाता है, फिर नाम, फिर वैकल्पिक रूप से प्रकार, और फिर प्रारंभिक मूल्य। यानी स्वचालित प्रकार का निष्कर्ष उपलब्ध है। चर आरंभिक होने चाहिए - यदि आप एक प्रारंभिक मूल्य निर्दिष्ट नहीं करते हैं, तो संकलन त्रुटि होगी। हालांकि, एक विशेष अपरिभाषित मूल्य प्रदान किया जाता है, जिसका उपयोग निर्विवाद रूप से चरों को निर्दिष्ट करने के लिए स्पष्ट रूप से किया जा सकता है।

 var i:i32 = undefined; 

कंसोल आउटपुट


प्रयोगों के लिए, हमें कंसोल को आउटपुट की आवश्यकता होती है - सभी उदाहरणों में, यह प्रयोग की जाने वाली विधि है। प्लग-इन के क्षेत्र में

 const warn = std.debug.warn; 

और कोड इस तरह लिखा है:

 warn("{}\n{}\n", false, "hi"); 

कंपाइलर में कुछ बग होते हैं, जो किसी पूर्णांक या फ्लोटिंग-पॉइंट नंबर को इस तरह से आउटपुट करने की कोशिश करते समय ईमानदारी से रिपोर्ट करता है:
त्रुटि: कंपाइलर बग: पूर्णांक और फ्लोट शाब्दिक रूप से वर्गाकार फ़ंक्शन को डाला जाना चाहिए। github.com/ziglang/zig/issues/557

डेटा प्रकार


आदिम प्रकार


प्रकार के नाम स्पष्ट रूप से रस्ट (i8, u8, ... i128, u128) से लिए गए हैं, बाइनरी सी संगतता के लिए विशेष प्रकार भी हैं, 4 प्रकार के फ्लोटिंग-पॉइंट प्रकार (f16, f32, f64, f128)। एक प्रकार का बूल है। एक प्रकार की शून्य लंबाई शून्य और एक विशेष नोटरी है, जिस पर मैं बाद में चर्चा करूंगा।

आप बिट्स में किसी भी लम्बाई के पूर्णांक प्रकारों का निर्माण 1 से 65535 तक कर सकते हैं। टाइप नाम I या u अक्षर से शुरू होता है, और फिर बिट्स में लंबाई लिखी जाती है।

 //  ! var j:i65535 = 0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF; 

हालाँकि, मुझे कंसोल में यह मान नहीं मिला - संकलन प्रक्रिया के दौरान LLVM में एक त्रुटि हुई।

सामान्य तौर पर, यह एक दिलचस्प समाधान है, हालांकि अस्पष्ट (IMHO: संकलक स्तर पर लंबे समय तक संख्यात्मक शाब्दिक समर्थन करना सही है, लेकिन इस तरह से नामकरण करना बहुत अच्छा नहीं है, इसे ईमानदारी से टेम्पलेट प्रकार के माध्यम से करना बेहतर है)। और सीमा 65535 क्यों है? GMP जैसी लाइब्रेरी इस तरह की पाबंदी नहीं लगाती हैं?

स्ट्रिंग शाब्दिक


ये चरित्र सरणियाँ हैं (अंत में शून्य को पीछे किए बिना)। एक समाप्ति शून्य के साथ शाब्दिक के लिए, उपसर्ग 'c' का उपयोग किया जाता है।

 const normal_bytes = "hello"; const null_terminated_bytes = c"hello"; 

अधिकांश भाषाओं की तरह, Zig अपने कोड (\ uNNNN, \ UNNNNNN जहां N एक हेक्साडेसिमल अंक है) के माध्यम से मानक एस्केप अनुक्रमों और यूनिकोड वर्णों को सम्मिलित करने का समर्थन करता है।
प्रत्येक पंक्ति की शुरुआत में दो बैकस्लैश का उपयोग करके मल्टी-लाइन शाब्दिक रूप से निर्मित होते हैं। कोई उद्धरण चिह्नों की आवश्यकता नहीं है। यही है, कच्चे तार बनाने के लिए कुछ प्रयास, लेकिन IMHO असफल है - कच्चे तार का लाभ यह है कि आप कोड में कहीं से भी कोई भी पाठ सम्मिलित कर सकते हैं - और आदर्श रूप से कुछ भी नहीं बदलता है, लेकिन यहां आपको प्रत्येक पंक्ति की शुरुआत में \\ जोड़ना होगा।

 const multiline = \\#include <stdio.h> \\ \\int main(int argc, char **argv) { \\ printf("hello world\n"); \\ return 0; \\} ; 

पूर्णांक शाब्दिक


सब कुछ si जैसी भाषाओं में है। मैं बहुत खुश था कि ऑक्टिकल शाब्दिकों के लिए, उपसर्ग 0o का उपयोग किया जाता है, और केवल शून्य नहीं, जैसा कि सी। 0b उपसर्ग के साथ बाइनरी शाब्दिक भी समर्थित हैं। फ्लोटिंग-पॉइंट शाब्दिक हेक्साडेसिमल हो सकता है (जैसा कि जीसीसी विस्तार में किया गया है )।

संचालन


बेशक, मानक अंकगणित, तार्किक और बिटवाइज सी ऑपरेशन हैं। संक्षिप्त संचालन समर्थित हैं (+ = आदि)। के बजाय && और || कीवर्ड और / या उपयोग किए जाते हैं। एक दिलचस्प बात यह है कि गारंटीकृत रैपराउंड शब्दार्थ के साथ संचालन को अतिरिक्त समर्थन दिया जाता है। वे इस तरह दिखते हैं:

 a +% b a +%= b 

इस मामले में, साधारण अंकगणितीय संचालन अतिप्रवाह की गारंटी नहीं देते हैं और अतिप्रवाह के दौरान उनके परिणामों को अपरिभाषित माना जाता है (और स्थिरांक के लिए संकलन त्रुटियां उत्पन्न होती हैं)। IMHO यह थोड़ा अजीब है, लेकिन जाहिरा तौर पर यह सी भाषा के शब्दार्थ के साथ संगतता के कुछ गहरे विचारों से बना है।

सरणियों


एरे शाब्दिक इस तरह दिखते हैं:

 const msg = []u8{ 'h', 'e', 'l', 'l', 'o' }; const arr = []i32{ 1, 2, 3, 4 }; 

स्ट्रिंग्स कैरेक्टर के एरे हैं, जैसे कि सी। वर्ग कोष्ठक के साथ क्लासिक इंडेक्सेशन। जोड़ (संयोजन) और सरणियों के गुणन के संचालन प्रदान किए जाते हैं। यह एक बहुत ही दिलचस्प बात है, और यदि सब कुछ सहमति के साथ स्पष्ट है, तो गुणा - मैं तब तक इंतजार करता रहा जब तक कि कोई इसे लागू नहीं करता है, और अब मैं इंतजार करता हूं :) असेंबलर (!) में एक ऐसा डुप्लिकेट ऑपरेशन है जो आपको डुप्लिकेट डेटा उत्पन्न करने की अनुमति देता है। अब जिग में:

 const one = []i32{ 1, 2, 3, 4 }; const two = []i32{ 5, 6, 7, 8 }; const c = one ++ two; // { 1,2,3,4,5,6,7,8 } const pattern = "ab" ** 3; // "ababab" 

संकेत


वाक्य रचना C के समान है।

 var x: i32 = 1234; //  const x_ptr = &x; //   

डेरेफेरिंग के लिए (पॉइंटर द्वारा मान लेना), एक असामान्य पोस्टफ़िक्स ऑपरेशन का उपयोग किया जाता है:

 x_ptr.* == 5678; x_ptr.* += 1; 

पॉइंटर प्रकार स्पष्ट रूप से टाइप नाम के सामने तारांकन सेट करके सेट किया गया है

 const x_ptr : *i32 = &x; 

स्लाइस (स्लाइस)


भाषा में बनाई गई एक डेटा संरचना जो आपको किसी सरणी या उसके भाग को संदर्भित करने की अनुमति देती है। पहले तत्व और तत्वों की संख्या को इंगित करता है। यह इस तरह दिखता है:

 var array = []i32{ 1, 2, 3, 4 }; const slice = array[0..array.len]; 

यह गो से लिया गया लगता है, निश्चित नहीं है। और मुझे यकीन नहीं है कि अगर यह किसी भाषा में एम्बेड करने लायक है, जबकि ऐसी किसी भी ओओपी भाषा में कार्यान्वयन बहुत प्राथमिक है।

संरचना


एक संरचना को घोषित करने का एक दिलचस्प तरीका: एक स्थिर घोषित किया जाता है, जिसका प्रकार स्वचालित रूप से "प्रकार" (प्रकार) के रूप में प्रदर्शित होता है, और यह वह है जिसे संरचना के नाम के रूप में उपयोग किया जाता है। और संरचना ही (संरचना) "नामहीन" है।

 const Point = struct { x: f32, y: f32, }; 

सी-लाइक भाषाओं में सामान्य तरीके से नाम निर्दिष्ट करना असंभव है, हालांकि, कंपाइलर कुछ नियमों के अनुसार टाइप नाम प्रदर्शित करता है - विशेष रूप से, ऊपर विचार किए गए मामले में, यह "प्रकार" स्थिरांक के नाम के साथ मेल खाएगा।

सामान्य तौर पर, भाषा फ़ील्ड के आदेश और स्मृति में उनके संरेखण की गारंटी नहीं देती है। यदि गारंटी की जरूरत है, तो "पैक" संरचनाओं का उपयोग किया जाना चाहिए।

 const Point2 = packed struct { x: f32, y: f32, }; 

शुरुआत - सिश्नी डिजाइनर्स की शैली में:

 const p = Point { .x = 0.12, .y = 0.34, }; 

संरचनाओं में विधियाँ हो सकती हैं। हालाँकि, एक संरचना में एक विधि रखना बस नाम स्थान के रूप में संरचना का उपयोग करना है; C ++ के विपरीत, कोई भी निहितार्थ इस पैरामीटर को पारित नहीं किया गया है।

स्थानांतरण


सामान्य तौर पर, C / C ++ में समान। मेटा-जानकारी तक पहुंचने के कुछ सुविधाजनक अंतर्निहित साधन हैं, उदाहरण के लिए, फ़ील्ड की संख्या और उनके नाम, जिसे भाषा में निर्मित सिंटैक्स मैक्रोज़ द्वारा कार्यान्वित किया जाता है (जिसे प्रलेखन में बिलियन फ़ंक्शन कहा जाता है)।

"सी के साथ द्विआधारी संगतता" के लिए कुछ बाहरी एनम प्रदान किए जाते हैं।

उस प्रकार को इंगित करने के लिए जिसे एन्यूमरेशन से गुजरना चाहिए, फॉर्म का निर्माण

 packed enum(u8) 

जहाँ u8 आधार प्रकार है।
Enums में संरचनाओं के समान तरीके हो सकते हैं (यानी नाम के रूप में एक गणना नाम का उपयोग करें)।

संघों (यूनियनों)


जैसा कि मैं इसे समझता हूं, जिग में संघ एक बीजीय प्रकार का योग है, अर्थात्। एक छिपा टैग फ़ील्ड है जो निर्धारित करता है कि संघ क्षेत्र में से कौन सा "सक्रिय" है। किसी अन्य क्षेत्र का "सक्रियण" पूरे संघ के पुनर्मूल्यांकन द्वारा किया जाता है। प्रलेखन उदाहरण

 const assert = @import("std").debug.assert; const mem = @import("std").mem; const Payload = union { Int: i64, Float: f64, Bool: bool, }; test "simple union" { var payload = Payload {.Int = 1234}; // payload.Float = 12.34; // !    assert(payload.Int == 1234); //       payload = Payload {.Float = 12.34}; assert(payload.Float == 12.34); } 

टैग के लिए यूनियन स्पष्ट रूप से गणना का उपयोग कर सकते हैं।

 // Unions can be given an enum tag type: const ComplexTypeTag = enum { Ok, NotOk }; const ComplexType = union(ComplexTypeTag) { Ok: u8, NotOk: void, }; 

गणना और संरचनाओं की तरह यूनियनों, तरीकों के लिए अपने स्वयं के नाम स्थान भी प्रदान कर सकते हैं।

वैकल्पिक प्रकार


जिग में बिल्ट-इन ऑप्शनल सपोर्ट है। प्रकार नाम से पहले एक प्रश्न चिह्न जोड़ा जाता है:

 const normal_int: i32 = 1234; // normal integer const optional_int: ?i32 = 5678; // optional integer 

दिलचस्प बात यह है कि, जिग ने एक संभावना के बारे में बात की जिसमें मुझे संदेह था, लेकिन यह सुनिश्चित नहीं था कि यह सही था या नहीं। अतिरिक्त छिपे हुए फ़ील्ड ("टैग") को जोड़े बिना विकल्पों के साथ संगत किया जाता है, जो मूल्य की वैधता का संकेत देता है; और अशक्त का उपयोग अमान्य मान के रूप में किया जाता है। इस प्रकार, पॉइंटर्स द्वारा Zig में दर्शाए गए संदर्भ प्रकारों को "वैकल्पिकता" के लिए अतिरिक्त मेमोरी की आवश्यकता नहीं है। इसी समय, नियमित रूप से संकेत करने के लिए शून्य मान निर्दिष्ट करना निषिद्ध है।

त्रुटि प्रकार


वे वैकल्पिक प्रकारों के समान हैं, लेकिन बूलियन टैग ("वास्तव में अमान्य") के बजाय, त्रुटि कोड के अनुरूप गणना तत्व का उपयोग किया जाता है। वाक्यविन्यास विकल्पों के समान है, एक प्रश्न चिह्न के बजाय एक विस्मयादिबोधक चिह्न जोड़ा जाता है। इस प्रकार, इन प्रकारों का उपयोग किया जा सकता है, उदाहरण के लिए, फ़ंक्शंस से लौटने के लिए: या तो फ़ंक्शन के सफल संचालन का ऑब्जेक्ट-परिणाम वापस आ जाता है, या संबंधित कोड के साथ एक त्रुटि वापस आ जाती है। त्रुटि प्रकार Zig भाषा त्रुटि हैंडलिंग प्रणाली का एक महत्वपूर्ण हिस्सा हैं, अधिक जानकारी के लिए त्रुटि हैंडलिंग अनुभाग देखें।

शून्य टाइप करें


शून्य में वैरिएबल और उनके साथ संचालन संभव है

 var x: void = {}; var y: void = {}; x = y; 

इस तरह के संचालन के लिए कोई कोड उत्पन्न नहीं होता है; यह प्रकार मुख्य रूप से मेटाप्रोग्रामिंग के लिए उपयोगी है।

C संगतता के लिए एक c_void प्रकार भी है।

नियंत्रण संचालक और कार्य


इनमें शामिल हैं: ब्लॉक, स्विच, जबकि, के लिए, यदि, अन्यथा, ब्रेक, जारी रखें। कोड को समूहित करने के लिए, मानक घुंघराले कोष्ठक का उपयोग किया जाता है। बस ब्लॉक, जैसा कि C / C ++ में किया जाता है, चर का दायरा सीमित करने के लिए उपयोग किया जाता है। ब्लॉक को भाव के रूप में माना जा सकता है। भाषा में कोई गोटो नहीं है, लेकिन ऐसे लेबल हैं जिनका उपयोग ब्रेक के साथ किया जा सकता है और बयान जारी रख सकते हैं। डिफ़ॉल्ट रूप से, ये ऑपरेटर छोरों के साथ काम करते हैं; हालांकि, यदि किसी ब्लॉक में एक लेबल है, तो आप इसका उपयोग कर सकते हैं।

 var y: i32 = 123; const x = blk: { y += 1; break :blk y; //   blk   y }; 

स्विच स्टेटमेंट ऑपरेटर से भिन्न होता है, जिसमें "फ़ालतू" नहीं होता है केवल एक शर्त (केस) निष्पादित की जाती है और स्विच से बाहर निकल जाता है। वाक्यविन्यास अधिक कॉम्पैक्ट है: मामले के बजाय, "=>" तीर का उपयोग किया जाता है। स्विच को एक अभिव्यक्ति भी माना जा सकता है।

जब तक और यदि कथन आम तौर पर सभी सी जैसी भाषाओं में समान होते हैं। कथन के लिए अधिक पसंद है foreach। उन सभी को भाव के रूप में माना जा सकता है। नई सुविधाओं में से, जबकि और साथ ही, अगर, एक और ब्लॉक हो सकता है जो निष्पादित करता है अगर कोई लूप पुनरावृत्ति नहीं था।

और यहां स्विच के लिए एक सामान्य विशेषता के बारे में बात करने का समय है, जबकि, जो किसी तरह से फॉरेक्स लूप की अवधारणा से उधार लिया गया है - "कैप्चरिंग" चर। यह इस तरह दिखता है:

 while (eventuallyNullSequence()) |value| { sum1 += value; } if (opt_arg) |value| { assert(value == 0); } for (items[0..1]) |value| { sum += value; } 

यहाँ, जबकि तर्क डेटा का एक निश्चित "स्रोत" है, जो वैकल्पिक हो सकता है, इसके लिए, एक सरणी या एक टुकड़ा, और दो ऊर्ध्वाधर लाइनों के बीच स्थित एक चर में "विस्तारित" मान होता है - अर्थात सरणी या स्लाइस का मौजूदा तत्व (या इसके लिए एक संकेतक), वैकल्पिक प्रकार का आंतरिक मूल्य (या इसके लिए एक सूचक)।

बयानों को गलत और गलत ठहराना


गो से दिया गया आस्थगित निष्पादन विवरण। यह उसी तरह से काम करता है - इस ऑपरेटर के तर्क को निष्पादित किया जाता है जब ऑपरेटर का उपयोग किया जाता है जिसमें गुंजाइश छोड़ देता है। इसके अलावा, ग़लती करने वाला ऑपरेटर प्रदान किया जाता है, जो सक्रिय त्रुटि कोड के साथ एक त्रुटि प्रकार फ़ंक्शन से वापस आने पर चालू हो जाता है। यह मूल Zig एरर हैंडलिंग सिस्टम का हिस्सा है।

अप्राप्य संचालक


अनुबंध प्रोग्रामिंग का तत्व। एक विशेष कीवर्ड, जिसे प्रबंधन के किसी भी परिस्थिति में नहीं आना चाहिए। यदि यह वहां पहुंचता है, तो डिबग और रिलीज़सैफ़ मोड में एक आतंक उत्पन्न होता है, और रिलीज़फ़ास्ट में ऑप्टिमाइज़र इन शाखाओं को पूरी तरह से बाहर फेंक देता है।

noreturn


तकनीकी रूप से, यह किसी अन्य प्रकार के साथ अभिव्यक्ति में संगत प्रकार है। यह इस तथ्य के कारण संभव है कि इस प्रकार की कोई वस्तु कभी वापस नहीं आएगी। चूंकि ऑपरेटर जिग में अभिव्यक्ति हैं, इसलिए अभिव्यक्ति के लिए एक विशेष प्रकार की आवश्यकता होती है जिसका मूल्यांकन कभी नहीं किया जाएगा। यह तब होता है जब अभिव्यक्ति का सही पक्ष अपरिवर्तनीय रूप से नियंत्रण को बाहर कहीं स्थानांतरित करता है। ऐसे बयानों के लिए, जारी, वापसी, अगम्य, अनंत लूप और फ़ंक्शन जो कभी भी नियंत्रण नहीं लौटाते हैं। तुलना के लिए, एक नियमित फ़ंक्शन के लिए एक कॉल (वापसी नियंत्रण) एक नोटरी ऑपरेटर नहीं है, क्योंकि हालांकि नियंत्रण को बाहर स्थानांतरित किया जाता है, यह जल्दी या बाद में कॉल के बिंदु पर वापस आ जाएगा।

इस प्रकार, निम्नलिखित अभिव्यक्तियाँ संभव हो जाती हैं:

 fn foo(condition: bool, b: u32) void { const a = if (condition) b else return; @panic("do something with a"); } 

वैरिएबल को मान / if स्टेटमेंट द्वारा लौटाया जाता है। इसके लिए, पुर्जों (यदि और दोनों) को एक ही प्रकार की अभिव्यक्ति वापस करनी चाहिए। यदि कोई भाग बूल देता है, तो दूसरा भाग नोटरी प्रकार है, जो तकनीकी रूप से किसी भी प्रकार के साथ संगत है, परिणामस्वरूप, कोड त्रुटियों के बिना संकलित होता है।

कार्यों


इस प्रकार की भाषाओं के लिए वाक्य रचना क्लासिक है:

 fn add(a: i8, b: i8) i8 { return a + b; } 

सामान्य तौर पर, फ़ंक्शन बहुत मानक दिखते हैं। अब तक मैंने प्रथम श्रेणी के कार्यों के संकेतों पर ध्यान नहीं दिया है, लेकिन भाषा के साथ मेरा परिचित बहुत सतही है, मैं गलत हो सकता हूं। हालांकि शायद अभी तक ऐसा नहीं किया गया है।

एक और दिलचस्प विशेषता यह है कि ज़िग में, लौटाए गए मानों की अनदेखी केवल अंडरस्कोर का उपयोग करके स्पष्ट रूप से की जा सकती है

  _ = foo(); 

एक प्रतिबिंब है जो आपको फ़ंक्शन के बारे में विभिन्न जानकारी प्राप्त करने की अनुमति देता है

 const assert = @import("std").debug.assert; test "fn reflection" { assert(@typeOf(assert).ReturnType == void); //    assert(@typeOf(assert).is_var_args == false); //    } 

संकलन समय पर कोड निष्पादन


जिग एक शक्तिशाली सुविधा प्रदान करता है - संकलन के समय में zig में लिखा कोड निष्पादित करना। संकलन के समय कोड को निष्पादित करने के लिए, बस इसे कंपार्टमेंट कीवर्ड वाले ब्लॉक में लपेटें। एक ही फ़ंक्शन को संकलित समय और रन समय दोनों में कहा जा सकता है, जो आपको सार्वभौमिक कोड लिखने की अनुमति देता है। बेशक, कोड के विभिन्न संदर्भों से जुड़ी कुछ सीमाएं हैं। उदाहरण के लिए, कई उदाहरणों में प्रलेखन में, संकलन समय की जांच करने के लिए उपयोग किया जाता है:

 // array literal const message = []u8{ 'h', 'e', 'l', 'l', 'o' }; // get the size of an array comptime { assert(message.len == 5); } 

लेकिन निश्चित रूप से इस ऑपरेटर की शक्ति यहां पूरी तरह से खुलासा से दूर है। तो, भाषा के विवरण में, वाक्यविन्यास मैक्रो के प्रभावी उपयोग का एक उत्कृष्ट उदाहरण दिया गया है - प्रिंटफ के समान एक फ़ंक्शन का कार्यान्वयन, लेकिन प्रारूप स्ट्रिंग को पार्स करना और संकलन चरण में सभी आवश्यक प्रकार के तर्कों की जांच करना।

इसके अलावा, कंपाइल शब्द का उपयोग कंपाइल-टाइम फ़ंक्शंस के मापदंडों को इंगित करने के लिए किया जाता है, जो C ++ टेम्पलेट फ़ंक्शंस के समान है।

    fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } 

हैंडलिंग में त्रुटि


ज़िग ने एक मूल त्रुटि हैंडलिंग प्रणाली का आविष्कार किया जो अन्य भाषाओं की तरह नहीं था। इसे "स्पष्ट अपवाद" कहा जा सकता है (इस भाषा में, गवाह आम तौर पर मुहावरों में से एक है)। यह गो रिटर्न कोड की तरह भी दिखता है, लेकिन यह अलग तरह से काम करता है।

Zig त्रुटि प्रसंस्करण प्रणाली कस्टम त्रुटि कोड (त्रुटि) को लागू करने के लिए विशेष गणना पर आधारित है और उनके आधार पर "त्रुटि प्रकार" (बीजीय प्रकार के योग, लौटे फ़ंक्शन प्रकार और त्रुटि कोड के संयोजन) पर आधारित है।

त्रुटि गणना को उसी तरह से घोषित किया जाता है जैसे नियमित गणना:

 const FileOpenError = error { AccessDenied, OutOfMemory, FileNotFound, }; const AllocationError = error { OutOfMemory, }; 

हालाँकि, सभी त्रुटि कोड शून्य से अधिक मूल्य प्राप्त करते हैं; इसके अलावा, यदि आप दो गणनाओं में एक ही नाम के साथ एक कोड घोषित करते हैं, तो इसे समान मूल्य प्राप्त होगा। हालांकि, त्रुटियों के विभिन्न गणना के बीच निहित रूपांतरण निषिद्ध हैं।

किसी भी तरह के कीवर्ड का अर्थ है एक गणना जिसमें सभी त्रुटि कोड शामिल हैं।

वैकल्पिक प्रकारों की तरह, भाषा विशेष वाक्यविन्यास का उपयोग करके त्रुटि प्रकार की पीढ़ी का समर्थन करती है। प्रकार! यू 64 किसी भी एरियर का संक्षिप्त रूप है! यू 64, जिसका अर्थ है एक संघ (विकल्प), जिसमें टाइप यू 64 और टाइप एनीटोर शामिल हैं (जैसा कि मैं इसे समझता हूं, कोड 0 त्रुटि की अनुपस्थिति को इंगित करने के लिए आरक्षित है और डेटा फ़ील्ड की वैधता बाकी कोड हैं। वास्तव में त्रुटि कोड)।

कैच कीवर्ड आपको त्रुटि को पकड़ने और डिफ़ॉल्ट मान में बदलने की अनुमति देता है:

 const number = parseU64(str, 10) catch 13; 

तो, यदि कोई त्रुटि parseU64 फ़ंक्शन में हो रही है! U64 प्रकार, तो इसे "इंटरसेप्ट" करेगा और 13 का डिफ़ॉल्ट मान लौटाएगा।

कोशिश कीवर्ड आपको ऊपरी स्तर पर त्रुटि को "आगे" करने की अनुमति देता है (अर्थात, कॉलिंग फ़ंक्शन के स्तर तक)। कोड देखें

 fn doAThing(str: []u8) !void { const number = try parseU64(str, 10); // ... } 

इसके बराबर:

 fn doAThing(str: []u8) !void { const number = parseU64(str, 10) catch |err| return err; // ... } 

यहाँ निम्न होता है: parseU64 कहा जाता है, अगर इसमें से कोई त्रुटि दी गई है - इसे कैच स्टेटमेंट द्वारा इंटरसेप्ट किया गया है, जिसमें एरर कोड को "कैप्चर" सिंटैक्स का उपयोग करके निकाला जाता है, जिसे गलत वैरिएबल में रखा गया है, जिसे माध्यम से लौटाया जाता है!

पहले वर्णित एर्देफर ऑपरेटर त्रुटि हैंडलिंग को भी संदर्भित करता है। कोड जो एक त्रुटिपूर्ण तर्क है, केवल तभी निष्पादित किया जाता है जब फ़ंक्शन एक त्रुटि देता है।

कुछ और संभावनाएं। का उपयोग कर || आप त्रुटि सेट को मर्ज कर सकते हैं

 const A = error{ NotDir, PathNotFound, }; const B = error{ OutOfMemory, PathNotFound, }; const C = A || B; 

Zig एरर ट्रेसिंग जैसे फीचर्स भी प्रदान करता है।यह स्टैक ट्रेस के समान है, लेकिन त्रुटि क्या हुई और कार्यक्रम के मुख्य समारोह में घटना के स्थान से प्रयास श्रृंखला के साथ कैसे प्रचारित किया गया, इसके बारे में विस्तृत जानकारी शामिल है।

इस प्रकार, ज़िग में त्रुटि से निपटने की प्रणाली एक बहुत ही मूल समाधान है, जो सी ++ में अपवाद या गो में रिटर्न कोड की तरह नहीं दिखता है। हम कह सकते हैं कि इस तरह के समाधान की एक निश्चित कीमत है - एक अतिरिक्त 4 बाइट्स, जो प्रत्येक लौटे मूल्य के साथ एक साथ वापस किया जाना चाहिए; स्पष्ट लाभ पूर्ण दृश्यता और पारदर्शिता हैं। C ++ के विपरीत, यहां फ़ंक्शन कॉल श्रृंखला की गहराई में कहीं से एक अज्ञात अपवाद नहीं फेंक सकता है। सभी फ़ंक्शन वापस लौटते हैं - यह स्पष्ट रूप से और केवल स्पष्ट रूप से लौटता है।

coroutine


जिग में बिल्ट-इन कॉरटाइन्स हैं। ये ऐसे कार्य हैं जो एसिंक्स कीवर्ड के साथ बनाए गए हैं, जिनकी मदद से आवंटनकर्ता और डीललोकेटर के कार्यों को स्थानांतरित किया जाता है (जैसा कि मैं इसे समझता हूं, एक अतिरिक्त स्टैक के लिए)।

 test "create a coroutine and cancel it" { const p = try async<std.debug.global_allocator> simpleAsyncFn(); comptime assert(@typeOf(p) == promise->void); cancel p; assert(x == 2); } async<*std.mem.Allocator> fn simpleAsyncFn() void { x += 1; } 

async एक विशेष प्रकार का वादा लौटाता है-> T (जहाँ T फ़ंक्शन का रिटर्न प्रकार है)। इस ऑब्जेक्ट का उपयोग करके, आप coroutine को नियंत्रित कर सकते हैं।

सबसे कम स्तरों में कीवर्ड शामिल हैं, फिर से शुरू, और रद्द करें। सस्पेंड का उपयोग करते हुए, coroutine निष्पादन को रोक दिया जाता है और कॉलिंग प्रोग्राम को पास कर दिया जाता है। सस्पेंड ब्लॉक का सिंटैक्स संभव है, ब्लॉक के अंदर सब कुछ निष्पादित किया जाता है जब तक कि कोरआउट वास्तव में निलंबित नहीं हो जाता।

रेज़्यूमे एक प्रकार का वादा करता है-> टी और फिर से शुरू करने वाले कोआउट को क्रियान्वित करता है जहां से इसे निलंबित किया गया था।

रद्द कर देता है coroutine स्मृति।

यह चित्र मुख्य कार्यक्रम (परीक्षण के रूप में) और कोरटाइन के बीच नियंत्रण के हस्तांतरण को दर्शाता है। सब कुछ काफी सरल है:

छवि

दूसरी (उच्च स्तर) सुविधा प्रतीक्षा का उपयोग है। यह केवल एक चीज है, स्पष्ट रूप से, मुझे समझ में नहीं आया (अफसोस, प्रलेखन अभी भी बहुत दुर्लभ है)। यहाँ प्रलेखन से थोड़ा संशोधित उदाहरण का वास्तविक नियंत्रण हस्तांतरण आरेख है, शायद यह आपको कुछ समझाएगा:

छवि

निर्मित कार्य


बिलियन फ़ंक्शंस - फ़ंक्शंस का एक बड़ा सेट जो भाषा में बनाया गया है और किसी भी मॉड्यूल के कनेक्शन की आवश्यकता नहीं है। शायद उनमें से कुछ को "बिल्ट-इन सिंटैक्टिक मैक्रोज़" कहना सही होगा, क्योंकि कई की क्षमताएं कार्यों से बहुत आगे निकल जाती हैं। प्रतिबिंब के माध्यम से बिल्डइन की पहुंच (sizeOf, tagName, TagType, typeInfo, typeName, typeOf), उनके सहायता मॉड्यूल (आयात) से जुड़े हैं। अन्य लोग क्लासिक बिल्ट-इन C / C ++ को अधिक पसंद करते हैं - वे निम्न-स्तरीय प्रकार रूपांतरणों को कार्यान्वित करते हैं, विभिन्न ऑपरेशन जैसे sqrt, popCount, slhExact, आदि। यह बहुत संभावना है कि जैसे-जैसे भाषा विकसित होगी, अंतर्निहित कार्यों की सूची बदल जाएगी।

निष्कर्ष में


यह बहुत सुखद है कि इस तरह की परियोजनाएं दिखाई देती हैं और विकसित होती हैं। हालांकि सी भाषा सुविधाजनक, संक्षिप्त और कई लोगों के लिए परिचित है, यह अभी भी पुरानी है और वास्तुशिल्प कारणों से कई आधुनिक प्रोग्रामिंग अवधारणाओं का समर्थन नहीं कर सकती है। C ++ विकसित हो रहा है, लेकिन प्रत्येक नए संस्करण के साथ उद्देश्यपूर्ण रूप से पुन: डिज़ाइन किया जा रहा है, यह अधिक कठिन होता जा रहा है, और समान वास्तु कारणों से और पिछड़े संगतता की आवश्यकता के कारण, इसके बारे में कुछ भी नहीं किया जा सकता है। जंग दिलचस्प है, लेकिन बहुत उच्च प्रवेश सीमा के साथ, जो हमेशा उचित नहीं है। डी एक अच्छा प्रयास है, लेकिन इसमें कुछ मामूली खामियां हैं, ऐसा लगता है कि शुरुआत में जावा के प्रभाव में भाषा को अधिक संभावना के साथ बनाया गया था, और बाद की विशेषताओं को किसी भी तरह किसी भी तरह से पेश किया गया था जैसा कि उन्हें नहीं होना चाहिए। जाहिर है, जिग इस तरह का एक और प्रयास है। भाषा दिलचस्प है, और यह देखना दिलचस्प है कि इससे क्या निकलता है।

Source: https://habr.com/ru/post/hi435872/


All Articles