Lua के साथ शुरुआत करना

API7.ai

September 23, 2022

OpenResty (NGINX + Lua)

NGINX की मूल बातों की सामान्य समझ के बाद, हम Lua को और अधिक सीखेंगे। यह OpenResty में उपयोग की जाने वाली प्रोग्रामिंग भाषा है, और इसके मूल सिंटैक्स को मास्टर करना आवश्यक है।

Lua एक छोटी और सूक्ष्म स्क्रिप्टिंग भाषा है, जो ब्राज़ील के एक विश्वविद्यालय प्रयोगशाला में जन्मी है, जिसका नाम पुर्तगाली में "सुंदर चंद्रमा" का अर्थ है। NGINX रूस में जन्मी, Lua ब्राज़ील में, और OpenResty चीन में लेखक के देश से आई है। दिलचस्प बात यह है कि ये तीनों समान रूप से चतुर ओपन सोर्स तकनीकें BRICS देशों से आई हैं, न कि यूरोप या अमेरिका से।

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

दूसरी ओर, हालांकि Lua की लाइब्रेरी अपेक्षाकृत सरल है, यह आसानी से C प्रोग्रामिंग भाषा की लाइब्रेरी को कॉल कर सकती है, और कई परिपक्व C प्रोग्रामिंग भाषा कोड इसके लिए उपयोग किए जा सकते हैं। उदाहरण के लिए, OpenResty में, आपको अक्सर NGINX और OpenSSL C प्रोग्रामिंग भाषा फ़ंक्शन्स को कॉल करने की आवश्यकता होगी, Lua और LuaJIT की C लाइब्रेरीज़ तक पहुंचने की क्षमता के कारण।

यहां, मैं आपको Lua डेटा प्रकार और सिंटैक्स से त्वरित परिचय दूंगा ताकि आप बाद में OpenResty को अधिक सुचारू रूप से सीख सकें।

पर्यावरण और हैलो वर्ल्ड

हमें मानक Lua 5.1 पर्यावरण को विशेष रूप से इंस्टॉल करने की आवश्यकता नहीं है क्योंकि OpenResty अब मानक Lua का समर्थन नहीं करता है, केवल LuaJIT का समर्थन करता है। ध्यान दें कि यहां मैं जो Lua सिंटैक्स प्रस्तुत कर रहा हूं, वह LuaJIT के साथ भी संगत है और Lua 5.3 पर आधारित नहीं है।

आप OpenResty इंस्टॉलेशन डायरेक्टरी में LuaJIT डायरेक्टरी और एक्ज़ीक्यूटेबल पा सकते हैं। मैं Mac पर्यावरण में हूं और OpenResty को इंस्टॉल करने के लिए brew का उपयोग किया है, इसलिए आपका स्थानीय पथ निम्नलिखित से भिन्न हो सकता है।

$ ll /usr/local/Cellar/openresty/1.13.6.2/luajit/bin/luajit lrwxr-xr-x 1 ming admin 18B 4 2 14:54 /usr/local/Cellar/openresty/1.13.6.2/luajit/bin/luajit -> luajit-2.1.0-beta3

आप इसे सिस्टम के एक्ज़ीक्यूटेबल फ़ाइल डायरेक्टरी में भी पा सकते हैं।

$ which luajit /usr/local/bin/luajit

LuaJIT का संस्करण जांचें।

$ luajit -v LuaJIT 2.1.0-beta2 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/

इस जानकारी की जांच करने के बाद, आप एक नई 1.lua फ़ाइल बना सकते हैं और LuaJIT का उपयोग करके hello world कोड चला सकते हैं।

$ cat 1.lua print("hello world") $ luajit 1.lua hello world

बेशक, आप इसे सीधे resty का उपयोग करके भी चला सकते हैं, यह जानते हुए कि यह अंततः LuaJIT के साथ भी निष्पादित होता है।

$ resty -e 'print("hello world")' hello world

hello world चलाने के ये दोनों तरीके संभव हैं। मैं resty तरीके को पसंद करता हूं क्योंकि बाद में OpenResty कोड भी resty द्वारा चलाया जाता है।

डेटा प्रकार

Lua में डेटा प्रकार बहुत अधिक नहीं हैं, और आप type फ़ंक्शन का उपयोग करके किसी मान का प्रकार वापस कर सकते हैं, जैसे कि निम्नलिखित।

$ resty -e 'print(type("hello world")) print(type(print)) print(type(true)) print(type(360.0)) print(type({})) print(type(nil)) '

निम्नलिखित जानकारी प्रिंट की जाएगी।

string function boolean number table nil

ये Lua में मूल डेटा प्रकार हैं। आइए उन्हें संक्षेप में परिचय दें।

स्ट्रिंग

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

आइए इस नुकसान को स्पष्ट करने के लिए एक उदाहरण लें। Lua में, हम स्ट्रिंग्स को जोड़ने के लिए दो डॉट चिह्नों का उपयोग करते हैं। निम्नलिखित कोड संख्याओं 1 से 10 को स्ट्रिंग्स के रूप में जोड़ता है।

$ resty -e 'local s = "" for i = 1, 10 do s = s .. tostring(i) end print(s)'

यहां हम दस बार लूप करते हैं, और केवल अंतिम परिणाम ही हमारी आवश्यकता होती है; बीच की नौ नई स्ट्रिंग्स अनावश्यक हैं। वे न केवल अतिरिक्त स्थान लेती हैं बल्कि अनावश्यक CPU ऑपरेशन्स भी खपत करती हैं।

बेशक, हमारे पास बाद में प्रदर्शन अनुकूलन अनुभाग में इसके लिए एक समाधान होगा।

इसके अलावा, Lua में, आपके पास स्ट्रिंग व्यक्त करने के तीन तरीके हैं: सिंगल कोट्स, डबल कोट्स, और लॉन्ग ब्रैकेट्स ([[]])। पहले दो अपेक्षाकृत समझने में आसान हैं और आमतौर पर अन्य भाषाओं में उपयोग किए जाते हैं, तो लॉन्ग ब्रैकेट्स का उपयोग क्या है?

आइए एक ठोस उदाहरण देखें।

$ resty -e 'print([[string has \n and \r]])' string has \n and \r

आप देख सकते हैं कि लॉन्ग ब्रैकेट्स में स्ट्रिंग्स किसी भी तरह से एस्केप नहीं की जाती हैं।

आप एक और सवाल पूछ सकते हैं: यदि उपरोक्त स्ट्रिंग में लॉन्ग ब्रैकेट्स शामिल हैं तो क्या होगा? जवाब सरल है: लॉन्ग ब्रैकेट्स के बीच में एक या अधिक = चिह्न जोड़ें।

$ resty -e 'print([=[ string has a [[]]. ]=])' string has a [[]].

बूलियन

यह एक सरल है, true और false। Lua में, केवल nil और false गलत हैं; बाकी सब सही है, जिसमें 0 और खाली स्ट्रिंग शामिल हैं। हम निम्नलिखित कोड के साथ इसकी पुष्टि कर सकते हैं।

$ resty -e 'local a = 0 if a then print("true") end a = "" if a then print("true") end'

इस प्रकार का निर्णय कई सामान्य विकास भाषाओं के साथ असंगत है, इसलिए ऐसे मामलों में त्रुटियों से बचने के लिए, आप तुलना के ऑब्जेक्ट को स्पष्ट रूप से लिख सकते हैं, जैसे कि निम्नलिखित।

$ resty -e 'local a = 0 if a == false then print("true") end '

संख्या

Lua का संख्या प्रकार डबल-प्रेसिशन फ्लोटिंग-पॉइंट संख्या के रूप में लागू किया गया है। यह उल्लेखनीय है कि LuaJIT द्वि-संख्या मोड का समर्थन करता है, जिसका अर्थ है कि LuaJIT पूर्णांकों को पूर्णांकों के रूप में और फ्लोटिंग-पॉइंट संख्याओं को डबल-प्रेसिशन फ्लोटिंग-पॉइंट संख्याओं के रूप में संग्रहीत करता है, संदर्भ के आधार पर।

इसके अलावा, LuaJIT बड़े पूर्णांकों के लिए लॉन्ग-लॉन्ग पूर्णांक का समर्थन करता है, जैसे कि निम्नलिखित उदाहरण।

$ resty -e 'print(9223372036854775807LL - 1)' 9223372036854775806LL

फ़ंक्शन

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

उदाहरण के लिए, निम्नलिखित दो फ़ंक्शन घोषणाएं बिल्कुल समान हैं।

function foo() end

और

foo = function () end

टेबल

टेबल Lua में एकमात्र डेटा संरचना है और स्वाभाविक रूप से बहुत महत्वपूर्ण है, इसलिए मैं इसे बाद में एक विशेष अनुभाग समर्पित करूंगा। हम एक सरल उदाहरण कोड से शुरू कर सकते हैं।

$ resty -e 'local color = {first = "red"} print(color["first"])' red

नल मान

Lua में, एक नल मान nil है। यदि आप एक वेरिएबल को परिभाषित करते हैं लेकिन इसे कोई मान नहीं देते हैं, तो इसका डिफ़ॉल्ट मान nil होता है।

$ resty -e 'local a print(type(a))' nil

जब आप OpenResty सिस्टम में प्रवेश करते हैं, तो आपको कई नल मान मिलेंगे, जैसे कि ngx.null, और इसी तरह। हम बाद में और बात करेंगे।

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

सामान्य मानक लाइब्रेरी

अक्सर, एक भाषा सीखना वास्तव में उसकी मानक लाइब्रेरी सीखना होता है।

Lua अपेक्षाकृत छोटी है और इसमें बहुत सारी मानक लाइब्रेरीज़ बिल्ट-इन नहीं हैं। इसके अलावा, OpenResty पर्यावरण में, Lua मानक लाइब्रेरी का प्राथमिकता बहुत कम है। एक ही फ़ंक्शन के लिए, मैं OpenResty API का उपयोग करने की सलाह देता हूं, LuaJIT की लाइब्रेरी फ़ंक्शन्स, और सामान्य Lua फ़ंक्शन्स।

OpenResty का API > LuaJIT की लाइब्रेरी फ़ंक्शन्स > मानक Lua के फ़ंक्शन्स एक प्राथमिकता है जो उपयोगिता और प्रदर्शन के संदर्भ में बार-बार उल्लेख की जाएगी।

हालांकि, इसके बावजूद, हम अपने वास्तविक प्रोजेक्ट्स में कुछ Lua लाइब्रेरीज़ का उपयोग करेंगे। यहां, मैंने कुछ अधिक सामान्यतः उपयोग की जाने वाली मानक लाइब्रेरीज़ का चयन किया है और उन्हें परिचय दिया है, और यदि आप अधिक जानना चाहते हैं, तो आप आधिकारिक Lua दस्तावेज़ीकरण की जांच कर सकते हैं।

स्ट्रिंग लाइब्रेरी

स्ट्रिंग मैनिपुलेशन वह है जो हम अक्सर उपयोग करते हैं और जहां सबसे अधिक गड्ढे हैं।

एक सरल नियम यह है कि यदि रेगुलर एक्सप्रेशन शामिल हैं, तो कृपया OpenResty द्वारा प्रदान किए गए ngx.re.* का उपयोग करके उन्हें हल करें, Lua के string.* प्रोसेसिंग का नहीं। ऐसा इसलिए है क्योंकि Lua का रेगुलर अद्वितीय है और PCRE विनिर्देश के अनुरूप नहीं है, और मुझे विश्वास है कि अधिकांश इंजीनियर इसे संभाल नहीं पाएंगे।

सबसे अधिक उपयोग की जाने वाली स्ट्रिंग लाइब्रेरी फ़ंक्शन्स में से एक है string.byte(s [, i [, j ]]), जो s[i], s[i + 1], s[i + 2], ------, s[j] वर्णों के अनुरूप ASCII कोड वापस करता है। i का डिफ़ॉल्ट मान 1 है, पहला बाइट, और j का डिफ़ॉल्ट मान i है।

आइए एक नमूना कोड देखें।

$ resty -e 'print(string.byte("abc", 1, 3)) print(string.byte("abc", 3)) -- तीसरा पैरामीटर गायब है, तीसरा पैरामीटर डिफ़ॉल्ट रूप से दूसरे के समान है, जो 3 है print(string.byte("abc")) -- दूसरा और तीसरा पैरामीटर गायब हैं, दोनों डिफ़ॉल्ट रूप से 1 हैं '

इसका आउटपुट है:

979899 99 97

टेबल लाइब्रेरी

OpenResty संदर्भ में, मैं Lua के साथ आने वाली अधिकांश टेबल लाइब्रेरीज़ का उपयोग करने की सलाह नहीं देता हूं, सिवाय कुछ फ़ंक्शन्स जैसे कि table.concat और table.sort के। उनके विवरण के लिए, हम उन्हें LuaJIT अध्याय के लिए छोड़ देंगे।

यहां मैं संक्षेप में table.concat का उल्लेख करूंगा। table.concat आमतौर पर स्ट्रिंग जोड़ने के परिदृश्यों में उपयोग किया जाता है, जैसे कि निम्नलिखित उदाहरण। यह बहुत सारी अनावश्यक स्ट्रिंग्स उत्पन्न करने से बच सकता है।

$ resty -e 'local a = {"A", "b", "C"} print(table.concat(a))'

गणित लाइब्रेरी

Lua गणित लाइब्रेरी में मानक गणितीय फ़ंक्शन्स का एक सेट होता है। गणित लाइब्रेरी का परिचय Lua प्रोग्रामिंग भाषा को समृद्ध करता है और प्रोग्राम लिखना आसान बनाता है।

OpenResty प्रोजेक्ट्स में, हम शायद ही कभी Lua का उपयोग गणितीय ऑपरेशन्स करने के लिए करते हैं। फिर भी, दो रैंडम संख्या से संबंधित फ़ंक्शन्स, math.random() और math.randomseed(), आमतौर पर उपयोग किए जाते हैं, जैसे कि निम्नलिखित कोड, जो एक निर्दिष्ट सीमा में दो रैंडम संख्याएं उत्पन्न कर सकता है।

$ resty -e 'math.randomseed (os.time()) print(math.random()) print(math.random(100))'

डमी वेरिएबल्स

इन साझा मानक लाइब्रेरीज़ को समझने के बाद, आइए एक नई अवधारणा सीखें - डमी वेरिएबल्स।

एक परिदृश्य की कल्पना करें जहां एक फ़ंक्शन कई मान वापस करता है, जिनमें से कुछ हमें आवश्यक नहीं हैं, तो हमें इन मानों को कैसे प्राप्त करना चाहिए?

मुझे नहीं पता कि आप इसके बारे में कैसा महसूस करते हैं, लेकिन मेरे लिए, कम से कम, इन अनुपयोगी वेरिएबल्स को सार्थक नाम देने की कोशिश करना कष्टप्रद है।

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

आइए मानक लाइब्रेरी फ़ंक्शन string.find को एक उदाहरण के रूप में लें ताकि डमी वेरिएबल्स के उपयोग को देख सकें। यह सामान्य लाइब्रेरी फ़ंक्शन दो मान वापस करता है, जो क्रमशः शुरुआत और अंत सबस्क्रिप्ट का प्रतिनिधित्व करते हैं।

यदि हम केवल शुरुआत सबस्क्रिप्ट प्राप्त करना चाहते हैं, तो string.find के रिटर्न मान को प्राप्त करने के लिए एक वेरिएबल घोषित करना सरल है, जैसा कि निम्नलिखित है।

$ resty -e 'local start = string.find("hello", "he") print(start)' 1

लेकिन यदि आप केवल अंत सबस्क्रिप्ट प्राप्त करना चाहते हैं, तो आपको डमी वेरिएबल का उपयोग करना होगा

$ resty -e 'local _, end_pos = string.find("hello", "he") print(end_pos)' 2

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

$ resty -e 'for _, v in ipairs({4,5,6}) do print(v) end' 4 5 6

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

सारांश

आज, हमने मानक Lua की डेटा संरचनाओं और सिंटैक्स का त्वरित अवलोकन किया है, और मुझे यकीन है कि आपको इस सरल और संक्षिप्त भाषा की पहली झलक मिल गई है। अगले पाठ में, मैं आपको Lua और LuaJIT के बीच संबंध के बारे में बताऊंगा, जिसमें LuaJIT OpenResty का मुख्य फोकस है और इसे गहराई से समझने लायक है।

अंत में, मैं आपको एक और विचारोत्तेजक प्रश्न छोड़ना चाहता हूं।

इस पोस्ट में जब हमने गणित लाइब्रेरी के बारे में सीखा तो उस कोड को याद रखें? यह एक निर्दिष्ट सीमा में दो रैंडम संख्याएं उत्पन्न करता है।

$ resty -e 'math.randomseed (os.time()) print(math.random()) print(math.random(100))'

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

हमारे साथ अपने विचार साझा करने के लिए आपका स्वागत है, और इस पोस्ट को अपने सहयोगियों और दोस्तों के साथ साझा करने के लिए भी आपका स्वागत है। आइए संवाद करें और साथ में सुधार करें।