लुआ का कोई "जारी" बयान क्यों नहीं है?


144

मैं पिछले कुछ महीनों में लूआ के साथ बहुत काम कर रहा हूं, और मुझे वास्तव में अधिकांश विशेषताएं पसंद हैं लेकिन मैं अभी भी उनमें से कुछ को याद कर रहा हूं:

  • क्यों नहीं है continue?
  • इसके लिए क्या वर्कअराउंड हैं?

12
चूंकि यह सवाल पूछा गया था, इसलिए लूआ को एक gotoबयान मिला, जिसे जारी रखने के लिए इस्तेमाल किया जा सकता है। नीचे दिए गए जवाब देखें।
lhf

जवाबों:


71

Lua 5.2 में गोटो का उपयोग करना सबसे अच्छा उपाय है:

-- prints odd numbers in [|1,10|]
for i=1,10 do
  if i % 2 == 0 then goto continue end
  print(i)
  ::continue::
end

यह संस्करण 2.0.1 के बाद से LuaJIT में समर्थित है


47
मुझे उम्मीद है कि वे एक वास्तविक continueएक दिन शामिल होंगे। gotoप्रतिस्थापन बहुत अच्छी लग रही है और अधिक लाइनों की जरूरत नहीं है। इसके अलावा, यदि आप एक से अधिक लूप एक फ़ंक्शन में ऐसा कर रहे हैं, तो यह परेशानी पैदा नहीं करेगा, दोनों के साथ ::continue::? प्रति पाश नाम बनाना एक अच्छी बात की तरह नहीं लगता है।
ईटी

66

जिस तरह से भाषा लेक्सिकल स्कोप का प्रबंधन करती है वह दोनों के साथ मुद्दों को पैदा करती है gotoऔर continue। उदाहरण के लिए,

local a=0
repeat 
    if f() then
        a=1 --change outer a
    end
    local a=f() -- inner a
until a==0 -- test inner a

local aलूप बॉडी के अंदर की घोषणा नामांकित बाहरी चर को मास्क करती है a, और उस स्थानीय का दायरा untilविवरण की स्थिति में फैला हुआ है, इसलिए स्थिति अंतरतम का परीक्षण कर रही है a

यदि continueअस्तित्व में है, तो यह केवल शब्दांश के दायरे में आने के बाद इसे केवल वैध होने के लिए प्रतिबंधित किया जाना चाहिए। यह उपयोगकर्ता के लिए दस्तावेज़ और कंपाइलर में लागू करने के लिए एक कठिन स्थिति है। इस मुद्दे के चारों ओर विभिन्न प्रस्तावों पर चर्चा की गई है, जिसमें लूप continueकी repeat ... untilशैली के साथ अस्वीकार करने का सरल उत्तर भी शामिल है । अब तक, किसी को भी भाषा में शामिल करने के लिए पर्याप्त सम्मोहक उपयोग का मामला नहीं रहा है।

आस-पास का काम आम तौर पर उस स्थिति को उलटने के लिए होता है, जो continueनिष्पादित होने का कारण बनती है , और शेष लूप बॉडी को उस स्थिति में एकत्रित करता है। तो, निम्नलिखित लूप

-- not valid Lua 5.1 (or 5.2)
for k,v in pairs(t) do
  if isstring(k) then continue end
  -- do something to t[k] when k is not a string
end

लिखा जा सकता है

-- valid Lua 5.1 (or 5.2)
for k,v in pairs(t) do
  if not isstring(k) then 
    -- do something to t[k] when k is not a string
  end
end

यह पर्याप्त रूप से स्पष्ट है, और आमतौर पर एक बोझ नहीं है जब तक कि आपके पास लूप ऑपरेशन को नियंत्रित करने वाले विस्तृत culls की एक श्रृंखला न हो।


5
एक अजगर पृष्ठभूमि से आ रहा है यह एक भ्रमित करने वाला उत्तर है क्योंकि वहाँ हर गुंजाइश पहले से ही जानता है कि चलने से पहले इसके स्थानीय चर क्या हैं। यानी मुझे पहुंचने के मामले में एक अनबाउंड स्थानीय चर त्रुटि की उम्मीद थी until...
ubershmekel

2
gotoLua 5.2 में आने से पहले Lua समुदाय में इसकी बहुत चर्चा हुई थी । स्वाभाविक रूप से, gotoएक ही मुद्दा है। उन्होंने अंततः निर्णय लिया कि जो भी रनटाइम और / या कोड जनरेशन की लागतों से रक्षा के लिए थे, वे एक लचीले होने के लाभों के लायक थे gotoजो कि दोनों continueऔर बहु-स्तर का अनुकरण करने के लिए उपयोग किया जा सकता है break। आपको विवरण प्राप्त करने के लिए संबंधित थ्रेड्स के लिए Lua सूची संग्रह खोजना होगा । चूंकि उन्होंने परिचय दिया था goto, इसलिए यह स्पष्ट नहीं था।
RBerteig

72
जारी रखने के कोड के बारे में "स्पष्ट रूप से पर्याप्त" कुछ भी नहीं है। यह एक सशर्त के अंदर घोंसला कोड के लिए एक नौसिखिया गलती है जहां एक निरंतर उपयोग किया जाना चाहिए था, और बदसूरत कोड लिखने की आवश्यकता है जैसे कि कोई सहानुभूति प्राप्त नहीं करनी चाहिए। बिल्कुल कोई बहाना नहीं है।
ग्लेन मेनार्ड

4
इस व्याख्या का कोई मतलब नहीं है। localकंपाइलर-केवल निर्देश है - इससे कोई फर्क नहीं पड़ता कि रनटाइम इंसट्रक्शन क्या हैं localऔर वेरिएबल उपयोग के लिए - समान स्कूपिंग व्यवहार को बनाए रखने के लिए आपको कंपाइलर में कुछ भी बदलने की आवश्यकता नहीं है। हां, यह इतना स्पष्ट नहीं हो सकता है और कुछ अतिरिक्त प्रलेखन की आवश्यकता है, लेकिन, फिर से दोहराने के लिए, इसे संकलक में शून्य परिवर्तन की आवश्यकता होती है। repeat do break end until trueमेरे जवाब में उदाहरण पहले से ही बिल्कुल बायटेकोड उत्पन्न करता है जो संकलक जारी रखेगा, केवल अंतर यह है कि इसके साथ continueआपको इसका उपयोग करने के लिए बदसूरत अतिरिक्त सिंटैक्स की आवश्यकता नहीं होगी।
ओलेग वी। वोल्कोव

7
कि आप परीक्षण कर सकते हैं आंतरिक चर त्रुटिपूर्ण डिजाइन के बारे में बोलता है। हालत आंतरिक दायरे से बाहर है और इसके भीतर चर तक पहुंच नहीं होनी चाहिए। C: में do{int i=0;}while (i == 0);विफल, या C ++ में बराबर पर विचार करें : do int i=0;while (i==0);भी विफल रहता है ("इस दायरे में घोषित नहीं किया गया था")। बहुत देर हो गई कि अब लुआ में, दुर्भाग्य से।
पेड्रो जिमनो

47

आप लूप बॉडी को अतिरिक्त रूप से लपेट सकते हैं repeat until trueऔर फिर do break endजारी रखने के प्रभाव के लिए अंदर का उपयोग कर सकते हैं । स्वाभाविक रूप से, यदि आपको वास्तव breakमें लूप से बाहर निकलने का इरादा है, तो आपको अतिरिक्त झंडे लगाने की आवश्यकता होगी।

यह हर बार 5, 1, 2 और 3 की छपाई करेगा।

for idx = 1, 5 do
    repeat
        print(1)
        print(2)
        print(3)
        do break end -- goes to next iteration of for
        print(4)
        print(5)
    until true
end

यह निर्माण भी JMPLua bytecode में शाब्दिक एक ओपोड के लिए अनुवाद करता है!

$ luac -l continue.lua 

main <continue.lua:0,0> (22 instructions, 88 bytes at 0x23c9530)
0+ params, 6 slots, 0 upvalues, 4 locals, 6 constants, 0 functions
    1   [1] LOADK       0 -1    ; 1
    2   [1] LOADK       1 -2    ; 3
    3   [1] LOADK       2 -1    ; 1
    4   [1] FORPREP     0 16    ; to 21
    5   [3] GETGLOBAL   4 -3    ; print
    6   [3] LOADK       5 -1    ; 1
    7   [3] CALL        4 2 1
    8   [4] GETGLOBAL   4 -3    ; print
    9   [4] LOADK       5 -4    ; 2
    10  [4] CALL        4 2 1
    11  [5] GETGLOBAL   4 -3    ; print
    12  [5] LOADK       5 -2    ; 3
    13  [5] CALL        4 2 1
    14  [6] JMP         6   ; to 21 -- Here it is! If you remove do break end from code, result will only differ by this single line.
    15  [7] GETGLOBAL   4 -3    ; print
    16  [7] LOADK       5 -5    ; 4
    17  [7] CALL        4 2 1
    18  [8] GETGLOBAL   4 -3    ; print
    19  [8] LOADK       5 -6    ; 5
    20  [8] CALL        4 2 1
    21  [1] FORLOOP     0 -17   ; to 5
    22  [10]    RETURN      0 1

4
यह उत्तर अच्छा है, लेकिन अभी भी सिर्फ एक के बजाय 3 लाइनों की आवश्यकता है। (यदि "जारी रखें" का ठीक से समर्थन किया गया था) यह एक गोटो लेबल की तुलना में थोड़ा प्रिटियर और सुरक्षित है, क्योंकि उस नाम के लिए संघर्ष के लिए नेस्टेड छोरों से बचने की आवश्यकता हो सकती है।
ET

3
हालाँकि, यह गोटो के साथ "वास्तविक" समस्या से बचने के लिए है कि आपको प्रत्येक पीडिडो-जारी के लिए एक नया पहचानकर्ता / लेबल का आविष्कार नहीं करना है और यह कम त्रुटि वाला है क्योंकि कोड समय के साथ संशोधित होता है। मैं मानता हूं कि जारी रखना उपयोगी होगा , लेकिन यह IMO अगली सबसे अच्छी बात है (और इसे दोहराने के लिए दो पंक्तियों की आवश्यकता होती है / जब तक बनाम एक अधिक औपचारिक "जारी"; ".. और तब भी, यदि आप उस रेखा से संबंधित थे; मायने रखता है कि आप हमेशा "दोहराएं" और "सच्चे अंत तक" लिख सकते हैं, उदाहरण के लिए: gist.github.com/wilson0x4d/f8410719033d1e0ef771 )
शॉन विल्सन

1
लोगों को वास्तव में प्रदर्शन पर विचार करने और यहां तक ​​कि luacSO पर आउटपुट प्रदान करने के लिए देखकर अच्छा लगा ! अच्छी तरह से
उत्तोलन करें

17

खुद लुआ के डिजाइनर से सीधे :

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


5
मुझे यह पसंद है: "दोनों उपयोगी हैं" "हम इसे करने नहीं जा रहे हैं" की व्याख्या के बाद सही है
डेविड लजंग मैडिसन स्टेलर

2
यह गुंजाइश है कि वे पता करने के लिए देख रहे थे जब उन्होंने ऐसा किया था, तो 5.2 में "गोटो" निर्माण जोड़कर (जो इस उत्तर के लिखे जाने पर जारी नहीं किया गया था)। इस उत्तर को 2012 से देखें , 5.2.0 जारी होने के बाद।
स्टुअर्ट पी। बेंटले

3
सही - क्योंकि 'गोटो' को एक अच्छी प्रोग्रामिंग कंस्ट्रक्शन माना जाता है। (अंत व्यंग्य) आह अच्छी तरह से।
डेविड लजंग मैडिसन स्टेलर

2
लेकिन यह अधिक उचित नहीं लगता था "मैं सिर्फ लूआ में डालना भूल गया था continue, क्षमा करें।"
नवदमुंड

17

पहले भाग का उत्तर अक्सर पूछे जाने वाले प्रश्न के रूप में दिया जाता है।

वर्कअराउंड के लिए, आप एक फंक्शन में लूप के शरीर को लपेट सकते हैं और returnउसी से, जैसे

-- Print the odd numbers from 1 to 99
for a = 1, 99 do
  (function()
    if a % 2 == 0 then
      return
    end
    print(a)
  end)()
end

या यदि आप दोनों breakऔर continueकार्यक्षमता चाहते हैं , तो स्थानीय फ़ंक्शन का परीक्षण करें, जैसे

local a = 1
while (function()
  if a > 99 then
    return false; -- break
  end
  if a % 2 == 0 then
    return true; -- continue
  end
  print(a)
  return true; -- continue
end)() do
  a = a + 1
end

16
कृपया नहीं। आप प्रत्येक पुनरावृत्ति पर क्लोजर वातावरण बनाते हैं और यह मेमोरी और जीसी चक्रों की बड़ी बर्बादी है।
ओलेग वी। वोल्कोव

4
collectgarbage("count")अपने सरल 100 प्रयासों के बाद भी जांच करें और फिर हम बात करेंगे। इस तरह के "समय से पहले" अनुकूलन ने पिछले हफ्ते हर मिनट एक रिबूट परियोजना को रिबूट करने से बचा लिया।
ओलेग वी। वोल्कोव

4
@ OracleV.Volkov जबकि यह उदाहरण जीसी पर एक अपेक्षाकृत उच्च भार डालता है, यह रिसाव नहीं करता है - सभी अस्थायी क्लोजर एकत्र किए जाएंगे। मुझे आपके प्रोजेक्ट के बारे में नहीं पता, लेकिन IME के ​​अधिकांश रीबूट्स लीक के कारण हैं।
फिन

10

मैंने पहले कभी लुआ का उपयोग नहीं किया है, लेकिन मैंने इसे गुगली दिया और इस के साथ आया:

http://www.luafaq.org/

प्रश्न 1.26 की जाँच करें ।

यह एक आम शिकायत है। लुआ लेखकों ने महसूस किया कि जारी रखना संभव नए नियंत्रण प्रवाह तंत्रों में से एक था (तथ्य यह है कि यह दोहराने के दायरे के नियमों के साथ काम नहीं कर सकता है / जब तक कि एक माध्यमिक कारक नहीं था।)

Lua 5.2 में, एक गोटो स्टेटमेंट है जिसे आसानी से एक ही काम करने के लिए इस्तेमाल किया जा सकता है।


8

हम इसे नीचे के रूप में प्राप्त कर सकते हैं, यह संख्याओं को भी छोड़ देगा

local len = 5
for i = 1, len do
    repeat 
        if i%2 == 0 then break end
        print(" i = "..i)
        break
    until true
end

ओ / पी:

i = 1
i = 3
i = 5

6

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

उदाहरण: कोड का इरादा i = 1 से i = 10 को छोड़कर i = 3 से स्टेटमेंट प्रिंट करना है। इसके अलावा यह "लूप स्टार्ट", लूप एंड "," इफ स्टार्ट ", और" इफ एंड "को अन्य नेस्टेड स्टेटमेंट्स को अनुकरण करने के लिए प्रिंट करता है जो आपके कोड में मौजूद हैं।

size = 10
for i=1, size do
    print("loop start")
    if whatever then
        print("if start")
        if (i == 3) then
            print("i is 3")
            --continue
        end
        print(j)
        print("if end")
    end
    print("loop end")
end

एक परीक्षण ध्वज के साथ लूप के अंतिम दायरे तक सभी शेष कथनों को संलग्न करके प्राप्त किया जाता है।

size = 10
for i=1, size do
    print("loop start")
    local continue = false;  -- initialize flag at the start of the loop
    if whatever then
        print("if start")
        if (i == 3) then
            print("i is 3")
            continue = true
        end

        if continue==false then          -- test flag
            print(j)
            print("if end")
        end
    end

    if (continue==false) then            -- test flag
        print("loop end")
    end
end

मैं यह नहीं कह रहा हूं कि यह सबसे अच्छा तरीका है लेकिन यह हमारे लिए पूरी तरह से काम करता है।


5

लुआ हल्की पटकथा वाली भाषा है जो संभव के रूप में छोटी करना चाहती है। उदाहरण के लिए, कई यूनिरी ऑपरेशन जैसे कि प्री / पोस्ट इंक्रीमेंट उपलब्ध नहीं है

जारी रखने के बजाय, आप गोटो का उपयोग कर सकते हैं

arr = {1,2,3,45,6,7,8}
for key,val in ipairs(arr) do
  if val > 6 then
     goto skip_to_next
  end
     # perform some calculation
  ::skip_to_next::
end

4

Inverting के साथ फिर से, आप बस निम्नलिखित कोड का उपयोग कर सकते हैं:

for k,v in pairs(t) do
  if not isstring(k) then 
    -- do something to t[k] when k is not a string
end

उलटा के साथ समस्या यह है कि अधिक बार नहीं एक श्रृंखला में कई सशर्त हैं (जैसे उपयोगकर्ता इनपुट को मान्य करने के लिए)। और क्योंकि रास्ते में किसी भी बिंदु पर शॉर्ट सर्किट होने की आवश्यकता हो सकती है, उलटा का मतलब है कि लगातार स्थिति को घोंसला बनाने के लिए "इसके बजाय यह बुरा है? तो बच; और यह बुरा है? फिर बच?", जो बहुत सीधा है। आप कोड के साथ समाप्त करते हैं जैसे "क्या यह ठीक है? तो क्या यह ठीक है? तो क्या यह ठीक है? फिर ऐसा करें" जो बहुत अधिक है।
लेस्ली क्रुसे

-2

क्यों जारी नहीं है?

क्योंकि यह अनावश्यक है। वहाँ बहुत कम स्थितियाँ हैं जहाँ एक देव को इसकी आवश्यकता होगी।

ए) जब आपके पास एक बहुत ही सरल लूप होता है, तो 1- या 2-लाइनर कहें, तो आप बस लूप की स्थिति को बदल सकते हैं और यह अभी भी बहुत पठनीय है।

बी) जब आप सरल प्रक्रियात्मक कोड लिख रहे हैं (उर्फ। हमने पिछली शताब्दी में कोड कैसे लिखा था), तो आपको संरचित प्रोग्रामिंग (उर्फ) भी लागू करना चाहिए। हमने पिछली शताब्दी में बेहतर कोड कैसे लिखा था)

ग) यदि आप ऑब्जेक्ट-ओरिएंटेड कोड लिख रहे हैं, तो आपके लूप बॉडी में एक या दो विधि कॉलों से अधिक नहीं होना चाहिए जब तक कि इसे एक या दो-लाइनर में व्यक्त नहीं किया जा सकता है (जिस स्थिति में, ए देखें)

डी) यदि आप कार्यात्मक कोड लिख रहे हैं, तो बस अगले पुनरावृत्ति के लिए एक सादा पूंछ-कॉल लौटाएं।

केवल तभी जब आप किसी continueकीवर्ड का उपयोग करना चाहते हैं यदि आप Lua को कोड करना चाहते हैं जैसे कि यह अजगर है, जो कि यह अभी नहीं है।

इसके लिए क्या वर्कअराउंड हैं?

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


कुछ स्पष्टीकरण:

¹ लुआ एक बहुत ही न्यूनतम भाषा है। यह कुछ सुविधाओं के रूप में इसे दूर करने की कोशिश कर सकता है, और एक continueबयान उस अर्थ में एक आवश्यक विशेषता नहीं है।

मुझे लगता है कि इस 2019 साक्षात्कार में रॉबर्टो इयरुसिलेम्स्की द्वारा अतिसूक्ष्मवाद के इस दर्शन को अच्छी तरह से कैप्चर किया गया है :

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

Other अन्य भाषाओं से लुआ में आने वाले प्रोग्रामरों का एक बड़ा समूह प्रतीत होता है क्योंकि जो भी कार्यक्रम वे उपयोग करने के लिए स्क्रिप्ट के लिए प्रयास कर रहे हैं, और उनमें से बहुत से लोग अपनी भाषा के अलावा कुछ भी लिखना नहीं चाहते हैं। पसंद, जो कई सवालों की ओर ले जाती है जैसे "Lua में X सुविधा क्यों नहीं है?"

मैत्ज़ ने हाल के एक साक्षात्कार में रूबी के साथ इसी तरह की स्थिति का वर्णन किया :

सबसे लोकप्रिय प्रश्न यह है: "मैं भाषा X समुदाय से हूं; क्या आप X से रूबी के लिए भाषा की विशेषता का परिचय नहीं दे सकते?", या उसके बाद कुछ। और इन अनुरोधों का मेरा सामान्य उत्तर है ... "नहीं, मैं ऐसा नहीं करूंगा", क्योंकि हमारे पास विभिन्न भाषा डिजाइन और विभिन्न भाषा विकास नीतियां हैं।

This इसके आसपास अपना रास्ता हैक करने के कुछ तरीके हैं; कुछ उपयोगकर्ताओं ने उपयोग करने का सुझाव दिया है goto, जो कि ज्यादातर मामलों में काफी अच्छा है, लेकिन बहुत जल्दी बदसूरत हो जाता है और नेस्टेड छोरों के साथ पूरी तरह से टूट जाता है। gotoजब भी आप अपना कोड किसी और को दिखाते हैं तो एस का उपयोग करने से आपके ऊपर फेंकी गई एसआईसीपी की एक प्रति होने का खतरा होता है।


1
मैंने अस्वीकार कर दिया क्योंकि बहुत पहला वाक्य स्पष्ट रूप से गलत है, और बाकी का जवाब अप्रभावी है।
21

सहायक नहीं? शायद; यह कुछ हद तक राय आधारित जवाब है। पहला वाक्य हालांकि स्पष्ट रूप से सच है; continueएक सुविधाजनक सुविधा हो सकती है, लेकिन यह जरूरी नहीं है । बहुत से लोग बिना इसके ठीक लुआ का उपयोग करते हैं, इसलिए वास्तव में इसके लिए ऐसा कोई मामला नहीं है जो एक साफ सुथरी विशेषता के अलावा कुछ भी हो जो किसी भी प्रोग्रामिंग भाषा के लिए आवश्यक नहीं है।
DarkWiiPlayer

यह एक तर्क नहीं है: आप यह तर्क नहीं दे सकते कि जब लोगों के पास कोई विकल्प नहीं होता है तो वे "इसके बिना ठीक हैं"।
bfontaine

मुझे लगता है कि हमारे पास तब "आवश्यक" की अलग-अलग परिभाषाएं हैं।
DarkWiiPlayer
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.