الإعلان عن المتغيرات وسؤال النطاق لـ Lua

StackOverflow https://stackoverflow.com/questions/1014757

  •  06-07-2019
  •  | 
  •  

سؤال

أنا المطور الرئيسي لـ بيتفايتر, ، ونحن نستخدم Lua كلغة برمجة نصية للسماح للاعبين ببرمجة سفن الروبوتات المخصصة الخاصة بهم.

في Lua، لا تحتاج إلى إعلان المتغيرات، وجميع المتغيرات افتراضية على النطاق العام، ما لم يتم الإعلان عن خلاف ذلك.وهذا يؤدي إلى بعض المشاكل.خذ المقتطف التالي على سبيل المثال:

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()‎ أي مرشحات، فسيظل العنصر الأقرب يشير إلى أي سفينة عثر عليها في المرة الأخيرة، وفي الفترة الفاصلة، كان من الممكن أن تُقتل تلك السفينة.إذا قُتلت السفينة، فإنها لم تعد موجودة، وسيفشل getFiringSolution().

هل لاحظت المشكلة؟حسنًا، لن يفعل ذلك المستخدمون أيضًا.إنها خفية، ولكن مع تأثير درامي.

أحد الحلول هو المطالبة بالإعلان عن جميع المتغيرات، وتعيين كافة المتغيرات افتراضيًا على النطاق المحلي.وفي حين أن هذا التغيير لن يجعل من المستحيل على المبرمجين الرجوع إلى كائنات لم تعد موجودة، فإنه سيجعل من الصعب القيام بذلك عن غير قصد.

هل هناك أي طريقة لإخبار Lua بضبط جميع المتغيرات على النطاق المحلي و/أو المطالبة بالإعلان عنها؟أعرف بعض اللغات الأخرى (على سبيل المثال.Perl) يتوفر هذا الخيار.

شكرًا!


الكثير من الإجابات الجيدة هنا، شكرا!

لقد قررت استخدام نسخة معدلة قليلاً من وحدة Lua "الصارمة".يبدو أن هذا يقودني إلى حيث أريد أن أذهب، وسأقوم باختراقه قليلاً لتحسين الرسائل وجعلها أكثر ملاءمة للسياق الخاص بي.

هل كانت مفيدة؟

المحلول

وليس هناك خيار لتعيين هذا السلوك، ولكن هناك وحدة نمطية "صارمة" المتوفرة مع تثبيت قياسي، التي تفعل ذلك تماما (عن طريق تعديل الفوقية الجداول). الاستعمال: تتطلب "صارمة"

لمزيد من المعلومات المتعمقة وغيرها من الحلول: http://lua-users.org/wiki / DetectingUndefinedVariables ، ولكن أوصي "صارمة".

نصائح أخرى

وشيء على.

في لوا، غلوبالس يعيش نظريا في _G غلوبالس الجدول (الواقع هو قليلا أكثر تعقيدا، ولكن من الجانب لوا ليس هناك طريقة لمعرفة AFAIK). كما هو الحال مع جميع الجداول لوا أخرى، فمن الممكن لإرفاق metatable __newindex إلى _G التي تتحكم في كيفية تضاف المتغيرات لذلك. السماح لهذا المعالج __newindex تفعل ما تريد القيام به عندما يقوم شخص عالمي: رمي خطأ، تسمح بذلك ولكن طباعة تحذير، الخ

لالعبث _G، فمن أبسط وأنظف لاستخدام setfenv. انظر الوثائق .

"المحلية بشكل افتراضي هي خطأ".لطفا أنظر

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

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

أنت بحاجة إلى استخدام نوع من حماية البيئة العالمية.هناك بعض الأدوات الثابتة للقيام بذلك (ليست ناضجة جدًا)، ولكن الحل الأكثر شيوعًا هو استخدام الحماية أثناء التشغيل، بناءً على __index و __newindex في _Gقابل للتحويل.

المكونات شاميلز:قد تكون هذه الصفحة مفيدة أيضًا:

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

لاحظ أنه بينما يناقش Lua المضمن في swf، فإن التقنية الموصوفة (انظر مصادر) القيام بعمل لوا عام.نحن نستخدم شيئًا على هذا المنوال في كود الإنتاج الخاص بنا في العمل.

والواقع، المتغير العالمي اضافية مع الإشارة قديمة إلى السفينة ستكون كافية للحفاظ على GC من التخلص من الكائن. حتى يمكن الكشف عن ذلك في وقت التشغيل عن طريق ملاحظة أن السفينة هي الآن "ميتة"، ورفض لفعل أي شيء معها. ولا يزال من غير السفينة الصحيحة، ولكن على الأقل كنت لا تحطم الطائرة.

وشيء واحد يمكنك القيام به هو الحفاظ على مخطوطات المستخدم في رمل أو ربما رمل في السيناريو. مع التلاعب الصحيح إما جدول بيئة رمل أو metatable لها، يمكنك ترتيب لنبذ كل أو معظم المتغيرات العالمية من رمل قبل (أو بعد) استدعاء التعليمات البرمجية للمستخدم.

وسوف تنظيف رمل بعد دعوات لديها ميزة التخلص إشارات إضافية إلى الأشياء التي لا ينبغي أن تسكع. ويمكن القيام بذلك عن طريق الحفاظ على القائمة البيضاء من المجالات التي يسمح لهم بالبقاء في البيئة، وحذف كل ما تبقى.

وعلى سبيل المثال، ما يلي ينفذ مكالمة سندبوإكسد إلى وظيفة يقدمها المستخدم مع بيئة تحتوي على أسماء المدرجة البيضاء فقط خلف طاولة الصفر الطازجة الموردة لكل المكالمة.

-- 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 إذا أردت.

لاحظ أن حل رمل الكامل ستنظر أيضا ما يجب القيام به حيال رمز المستخدم الذي قصد (أو خبيثة) ينفذ لانهائية (أو مجرد طويلة جدا) حلقة أو عملية أخرى. حلول عامة لهذا هي موضوع عرضية من النقاش حول لوا قائمة ، ولكن حلول جيدة صعبة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top