2009-06-18 18 views
5

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

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

loc = bot:getLoc() 
items = bot:findItems(ShipType)  -- Find a Ship 

minDist = 999999 
found = false 

for indx, item in ipairs(items) do   
    local d = loc:distSquared(item:getLoc()) 

    if(d < minDist) then 
     closestItem = item 
     minDist = d 
    end 
end 

if(closestItem != nil) then 
    firingAngle = getFiringSolution(closestItem) 
end 

, अगर findItems() कोई उम्मीदवारों देता है, तो closestItem अभी भी जो कुछ भी जहाज पिछली बार के आसपास पाया करने के लिए और, संदर्भित करेंगे, बीच समय में है कि जहाज मारा जा सकता था। यदि जहाज मारे गए हैं, तो यह अब मौजूद नहीं है, और getFiringSolution() विफल हो जाएगा।

क्या आपने समस्या को देखा? खैर, न ही मेरे उपयोगकर्ता। यह सूक्ष्म है, लेकिन नाटकीय प्रभाव के साथ।

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

क्या लुआ को स्थानीय वर्प में सभी वर्रों को डिफ़ॉल्ट रूप से बताने का कोई तरीका है, और/या यह घोषित करने की आवश्यकता है कि उन्हें घोषित किया जाए? मुझे कुछ अन्य भाषाओं (जैसे पर्ल) पता है कि यह विकल्प उपलब्ध है।

धन्यवाद!


यहां बहुत सारे अच्छे उत्तर, धन्यवाद!

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

+0

बीटीडब्ल्यू, क्या आपके पास बयान के अंदर अतिरिक्त ब्रेसिज़ डालने का कोई अच्छा कारण है? –

+0

ठीक है, इससे पहले कि आप सवाल उठाएंगे, मैंने जवाब दिया होगा कि उन्हें आवश्यक था। लेकिन अब मुझे जवाब देना है कि माता-पिता को छोड़कर मुझे गलत लगता है! – Watusimoto

+2

यह निश्चित रूप से व्यक्तिगत पसंद है। लेकिन यह याद रखना महत्वपूर्ण है कि लुआ सी या पास्कल या जो कुछ भी नहीं है। लुआ लुआ है और इसे प्रभावी ढंग से उपयोग करने के लिए आपको इसका उपयोग करना चाहिए, ऐसा नहीं है कि यह अन्य प्रोग्रामिंग भाषा के लिए कुछ खराब विकल्प है। मैंने पाया है कि इस तरह का "वाक्यविन्यास गलत दिखता है" चीजें लुआ को मेरे दिमाग के हिस्से में सी ++ और अन्य भाषाओं से अलग रखने में मदद करती हैं। संक्षेप में, मेरी राय है: यदि यह लुआ में लिखा गया है, तो इसे लुआ रास्ते में लिखें! :-) –

उत्तर

3

इस व्यवहार को सेट करने का कोई विकल्प नहीं है, लेकिन मानक स्थापना के साथ प्रदान किया गया मॉड्यूल 'सख्त' है, जो वास्तव में (मेटा-टेबल को संशोधित करके) करता है। उपयोग: 'सख्त'

अधिक गहराई से जानकारी और अन्य समाधान के लिए आवश्यकता होती है: http://lua-users.org/wiki/DetectingUndefinedVariables, लेकिन मेरा सुझाव है 'सख्त'।

+0

यह सबसे आसान जवाब प्रतीत होता है, और यही वह है जिसे मैं ढूंढ रहा था।मैं यह देखने के लिए यहां सुझाए गए अन्य समाधानों को बेहतर ढंग से समझना चाहता हूं कि 'सख्त' का उपयोग करने में कोई कमी है या नहीं। – Watusimoto

2

सॉर्टा।

लुआ में, ग्लोबल्स वैश्विक रूप से ग्लोबल्स तालिका _G में रहते हैं (वास्तविकता थोड़ा अधिक जटिल है, लेकिन लुआ पक्ष से AFAIK को बताने का कोई तरीका नहीं है)। अन्य सभी लुआ टेबल के साथ, __newindex_G पर मेटाटेबल को संलग्न करना संभव है जो नियंत्रित करता है कि इसमें चर कैसे जोड़े जाते हैं। इस __newindex हैंडलर जो भी आप करना चाहते हैं, जब कोई व्यक्ति एक वैश्विक बनाता है:

_G साथ दखल करने के लिए एक त्रुटि फेंक, यह की अनुमति लेकिन एक चेतावनी मुद्रित, आदि, यह सबसे सरल और साफ setfenv उपयोग करने के लिए है। documentation देखें।

0

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

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

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

उदाहरण के लिए, निम्नलिखित उपयोगकर्ता द्वारा आपूर्ति किए गए फ़ंक्शन को एक सैंडबॉक्स किए गए कॉल को एक वातावरण के साथ लागू करता है जिसमें प्रत्येक कॉल के लिए आपूर्ति की गई ताजा स्क्रैच तालिका के पीछे केवल सफेद सूचीबद्ध नाम होते हैं।

 
-- table of globals that will available to user scripts 
local user_G = { 
     print=_G.print, 
     math=_G.math, 
     -- ... 
    } 
-- metatable for user sandbox 
local env_mt = { __index=user_G } 


-- call the function in a sandbox with an environment in which new global 
-- variables can be created and modified but they will be discarded when the 
-- user code completes. 
function doUserCode(user_code, ...) 
    local env = setmetatable({}, env_mt) -- create a fresh user environment with RO globals 
    setfenv(user_code, env)  -- hang it on the user code 
    local results = {pcall(user_code, ...)} 
    setfenv(user_code,{}) 
    return unpack(results) 
end 

यह केवल पढ़ने के लिए एक और metatable पहुंच के पीछे इसे वापस धक्का यदि आप चाहते थे द्वारा वैश्विक तालिका बनाने के लिए बढ़ाया जा सकता है।

ध्यान दें कि एक पूर्ण सैंडबॉक्स समाधान यह भी विचार करेगा कि उपयोगकर्ता कोड के बारे में क्या करना है जो गलती से (या दुर्भावनापूर्ण रूप से) एक अनंत (या केवल बहुत लंबा) लूप या अन्य ऑपरेशन निष्पादित करता है। इसके लिए सामान्य समाधान Lua list पर चर्चा का एक सामयिक विषय है, लेकिन अच्छे समाधान मुश्किल हैं।

+0

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

2

"डिफ़ॉल्ट रूप से स्थानीय गलत" है। कृपया

http://lua-users.org/wiki/LocalByDefault

http://lua-users.org/wiki/LuaScopingDiscussion

आप वैश्विक पर्यावरण संरक्षण किसी तरह का उपयोग करने की आवश्यकता को देखते हैं। ऐसा करने के लिए कुछ स्थिर उपकरण हैं (बहुत परिपक्व नहीं), लेकिन सबसे सामान्य समाधान __index और __newindex_G के मेटाटेबल में रनटाइम सुरक्षा का उपयोग करना है।

Shameles प्लग: यह पेज भी उपयोगी हो सकता है:

http://code.google.com/p/lua-alchemy/wiki/LuaGlobalEnvironmentProtection

नोट कि जब यह चर्चा करता लुआ swf में एम्बेड, वर्णित तकनीक (sources देखें) सामान्य लुआ लिए काम करते हैं। हम काम पर हमारे उत्पादन कोड में इन लाइनों के साथ कुछ का उपयोग करते हैं।

+1

डिफ़ॉल्ट रूप से स्थानीय (तर्कसंगत) गलत है, लेकिन फिर डिफ़ॉल्ट रूप से वैश्विक है! मैंने आपके द्वारा इंगित कोड को देखा, और ऐसा लगता है कि यह ऊपर सुझाए गए 'सख्त' मॉड्यूल का उपयोग करने के समान कुछ करता है। क्या वे किसी भी महत्वपूर्ण तरीके से भिन्न हैं? – Watusimoto

+0

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

+0

मुख्य अंतर (उन सख्त मॉड्यूल के बीच) यह है कि मेरा वैश्विक चर के स्पष्ट और संक्षिप्त घोषणा को मजबूर करने की कोशिश करता है (जैसा कि मैं उन्हें अपने कोड में छुटकारा पाने के लिए बुरी चीजों के रूप में देखता हूं - वैश्विक कार्यों सहित)। लुआ इत्यादि/सख्त.लुआ थोड़ा कम स्पष्ट है। लेकिन यह एक व्यक्तिगत वरीयता है। –