Является ли это проблемой области видимости переменной lua (и как ее можно решить)?

#lua

#lua

Вопрос:

Очень странная ошибка, показывающая, что объект равен нулю.

код в теме

 while pbs:HasNext() do
    local char = self.DecodeCharacter(pbs)
    ...
  

Можно было бы подумать, что если pbs:HasNext() есть true , это означает, что pbs нет nil , вообще.

Однако печать (pbs) — первая строка HTMLEntityCodec:DecodeCharacter отпечатков nil

 function HTMLEntityCodec:DecodeCharacter(pbs)
    print(pbs)
    ...
  

Весь файл, размещенный ниже, был удален с 1800 строк до 110, чтобы пользователям SO было понятно, как получить контекст. Но это удаление убрало всю логику из кода, так что не смущайтесь этим.

 #!/usr/bin/env lua

function Inherits( baseClass )
    local new_class = {}
    local class_mt = { __index = new_class }

    function new_class:create()
        local newinst = {}
        setmetatable( newinst, class_mt )
        return newinst
    end

    if baseClass then
        setmetatable( new_class, { __index = baseClass } )
    end

    return new_class
end


-------------------------------------------
-- PushbackString
-------------------------------------------
PushbackString = Inherits({})

function PushbackString:Init(input)
    self.input = input
    self.pushback = nil
    self.temp = nil
    self.index = 0 
    self.mark = 0
end

-- Mark the current index, so the client can reset() to it if need be.        
function PushbackString:HasNext()
    return true
end

function PushbackString:Mark ()
    self.temp = self.pushback
    self.mark = self.index
end


BaseCodec = Inherits({}) 

function BaseCodec:Decode(input)
    local buff = ''    
    local pbs = PushbackString:create()

    pbs:Init(input)

    while pbs:HasNext() do
        local char = self.DecodeCharacter(pbs)
        if char ~= nil then
            buff = buff .. char
        else
            buff = buff .. pbs:Next()
        end
    end
    return buff
end


HTMLEntityCodec = Inherits(BaseCodec)
-- HTMLEntityCodec.classname = ('HTMLEntityCodec')

function HTMLEntityCodec:DecodeCharacter(pbs)
    print(pbs)
    pbs:Mark()    
end

DefaultEncoder = Inherits({})

function DefaultEncoder:Init(codecs)
    self.html_codec = HTMLEntityCodec:create()
end

function DefaultEncoder:TestInput(input , strict)
    print ("n----------------8<----------------8<----------------n")
    print ("Input:t" .. input)
    -- default value
    if strict == nil then strict = true end

    -- nothing to do
    if input == nil then return nil end

    local working = input
    local codecs_found = {}
    local found_count = 0
    local clean = false

    while not clean do
        clean = true
        old = working
        working = self.html_codec:Decode( working )
        if old ~= working then
            print ("Warning:tINTRUSION DETECTED")
        end
    end

    print ("Output:t".. working)
    return working
end


local default_encoder = DefaultEncoder:create()
default_encoder:Init()
default_encoder:TestInput("%", true)

----------8<-----------8<--------------8<----------------
  

КОНЕЦ ФАЙЛА

Вывод на консоль:

 tzury@1005:~/devel/lua$ lua problem.lua 

----------------8<----------------8<----------------

Input:  %25
nil
lua: problem.lua:70: attempt to index local 'pbs' (a nil value)
stack traceback:
        problem.lua:70: in function 'DecodeCharacter'
        problem.lua:54: in function 'Decode'
        problem.lua:96: in function 'TestInput'
        problem.lua:109: in main chunk
        [C]: ?
  

Комментарии:

1. Ваша переменная ‘codec’ является глобальной — это задумано? Если нет, попробуйте изменить его на локальную переменную следующим образом: local codec = DefaultCodec:create() и также local char = self.Decode(codec) .

2. @MichalKottman, он был локальным, но я изменил его на глобальный из-за проблемы, с которой я столкнулся, которая не решила проблему. Это довольно странно, поскольку codec:HasNext() означает, что кодек не равен нулю, почему self.Decode он получает codec значение nil? первая строка self.decode is print... , которая показывает, что это nil

3. Вы не показываете реализацию DefaultCodec , поэтому трудно догадаться, что на самом деле происходит. Я предполагаю, что вы вызываете это однопоточным способом, без сопрограммирования, поэтому единственное место, где codec может быть изменено, — это само по DefaultCodec себе.

4. @MichalKottman Я только что сократил код с 1800 строк до 110, что является минимальным подмножеством, и проблема все еще существует. Код может не иметь никакого логического смысла, но игнорируйте это

Ответ №1:

В вашем коде сбой происходит в этой строке:

 local char = self.DecodeCharacter(pbs)
  

Проблема в том, что вы вызываете DecodeCharacter с неправильным количеством аргументов.

Решение: назовите это так (обратите внимание на двоеточие):

 local char = self:DecodeCharacter(pbs)
  

Объяснение:

Когда вы определяете функции в Lua с помощью двоеточия ( : ), вы используете синтаксический сахар, который скрывает неявный первый аргумент с именем self . Такие определения, как:

 function HTMLEntityCodec:DecodeCharacter(pbs) ... end
  

На самом деле «переведены» на это:

 HTMLEntityCodec.DecodeCharacter = function (self, pbs) ... end
  

Когда вы вызываете функцию, вам нужно либо самостоятельно передать self аргумент, либо использовать вызов двоеточия для его автоматической подачи. В вашем code ( self.DecodeCharacter(pbs) ) вы передаете pbs , что заканчивается как self в HTMLEntityCodec.DecodeCharacter , и pbs заканчивается как nil . Оба следующих вызова эквивалентны и должны решить проблему:

 local char = self.DecodeCharacter(self, pbs)
local char = self:DecodeCharacter(pbs)