Добавьте метод в строку и измените себя в Lua

#string #lua #io #luajit

Вопрос:

Как я могу добавить метод в string таблицу и изменить себя внутри нее ?

В принципе, я пытаюсь имитировать поведение io.StringIO.read метода в python, который считывает n символы в строке и возвращает их, изменяя строку, «потребляя» ее.

Я попробовал это:

 function string.read(str, n)
  to_return = str:sub(1, n)
  str = str:sub(n   1)
  return to_return
end

local foo = "heyfoobarhello"
print(string.read(foo, 3))
print(foo)
 

Выход есть:

 hey
heyfoobarhello
 

Я ожидал, что вторая строка будет только foobarhello .

Как я могу этого достичь ?

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

1. Строки в Lua неизменяемы. Вы можете обернуть строку как объект, который отслеживает, с чего начать. Или вы можете изменить API, чтобы возвращать строку и подстроку.

2. @lhf я понимаю, спасибо.

Ответ №1:

Чтобы имитировать io.StringIO класс Python, вы должны создать объект, который хранит как базовую строку, так и текущую позицию в этой строке. Чтение из потока ввода-вывода обычно не изменяет базовые данные.

 local StringIO_mt = {
  read = function(self, n)
    n = n or #self.buffer - self.position   1
    local result = self.buffer:sub(self.position, self.position   n - 1)
    self.position = self.position   n
    return result
  end,
}
StringIO_mt.__index = StringIO_mt

local function StringIO(buffer)
  local o = {buffer = buffer, position = 1}
  setmetatable(o, StringIO_mt)
  return o
end

local foo = StringIO"heyfoobarhello"
print(foo:read(3))
print(foo:read())
 

Выход:

 hey
foobarhello
 

Я не рекомендую добавлять этот класс или метод в string библиотеку Lua, потому что объект должен быть более сложным, чем просто строка.

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

1. Почему вы пишете код только для 5.4? У вопроса есть LuaJIT тег, это означает Lua 5.1.

2. @EgorSkriptunoff Да, я сам это понял, я просто удалил теги <something> . Не беспокойтесь 😉

3. @EgorSkriptunoff: Я совершенно пропустил этот тег. Исправлено.

Ответ №2:

Вы можете добавлять методы в строку типа данных независимо от таблицы строк.
Короткий пример, который показывает, что строковые методы работают даже в том случае, если таблица строк удаляется…

 string=nil

return _VERSION:upper():sub(1,3)
-- Returning: LUA
 

Таким образом, вы можете добавить метод…

 -- read.lua
local read = function(self, n1, n2)
return  self:sub(n1, n2)
end

getmetatable(_VERSION).__index.read=read

return read
 

…для всех строк.
( Не только _ВЕРСИЯ )

И используй это…

 do require('read') print(_VERSION:read(1,3):upper()) end
-- Print out: LUA