Lyubov
akamit
привет чат. подскжите пожалуйста как сделать подобное
string.format("%s %q", nil, "Lua user!")
akamit
то есть %s же как бэ имеет ввиду что это строковое значение, а он на nil ругается. можно конечно сделать tostring(nil) но этоже лишние символы)
Alexey
Lua > 5.1 и LuaJIT так работают вроде
Alexey
А для Lua 5.1 писать свою версию :)
Alexey
https://github.com/moteus/lua-log/blob/master/lua/log/formatter/pformat.lua
akamit
ага. у меня как раз 5.1
akamit
центос такой центос...
Alexey
можно написать простую функцию например с vararg библиотекой
local va = require "vararg"
local nil2s = function(v) return v == nil and 'nil' or v end
local format = function(fmt, ...) return string.format(fmt, va.map(nil2s, ...)) end
Ну или писать свой разборщик, что бы сделать его совсем безопасным.
Т.к. format("%d", nil) все равно вызывает ошибку
Anonymous
мяу?
Anonymous
во, работает :3
Snusmumriken
Anonymous
http://i.imgur.com/fdKS45O.png
Snusmumriken
Курлык.
Стикеры не работают?
Кто это?
Транслятор телеги в жабу?
Anonymous
дак я же про это говорил
Anonymous
стикеры приходят ссылками на контент)
Anonymous
чому?
Snusmumriken
Курлык-курлык.
Осталось сделать изображения нормальные.
Жаба, по моему, их тянет.
Anonymous
жаба может в HTML-сообщения
Anonymous
но не всякая
Snusmumriken
Мне нужно больше стикеров с нарушениями психики
Snusmumriken
Anonymous
[10:46:36] [g] lua: [User: Snusmumriken|UID:237976911|MID:17994]
[MessageMediaDocument] [Sticker 📖] http://tlgrm.rxtx.us/media/e6be75c8740a9e52883e9881f431616f2f7fe809ffcacbd813de5459cdf6c2cc.webp
Elias
Есть
Elias
Потому что tree.__index вызывается, а там tree[key], который не существует, поэтому снова вызывается __index
Elias
__index в итоге вызывается когда-нибудь или нет?
Наверное из-за него stack overflow?
Elias
local tree = {
f = function()
print("HELLO")
end
}
tree.__mt = {
__index = function(self, key)
return self.__data[key] or self[key] or tree[key]
end,
__newindex = function(self, key, value)
self.__data[key] = value
end
}
print(tree:f())
Вот это работает
Elias
Просто тут нужно все функции таблицы tree копировать в obj, когда tree:new() вызывается
Elias
Иначе у создаваемого объекта не будет addChild ключа и функции
Saphire
rawset
Saphire
Или как оно там
Snusmumriken
Иначе у создаваемого объекта не будет addChild ключа и функции
__index - это как раз такая штука, которая придумана "чтобы не копировать".
Если плодятся тысячи и миллионы объектов, копии ссылок на каждый метод у каждого объекта занимают нехило памяти, и требуют время на копирование.
Присобачить одну ссылку на метатаблицу быстрее, чем дублировать сразу много ссылок по списку. И сериализовать объекты исключительно с данными - проще.
Хотя и доступ теоретически чуть быстрее (не вызывается __index).
Поэтому у очень мелких объектов с одним-двумя методами (которые не надо сериализовать) эффективнее копировать методы, а у объектов с кучей методов которые не очень часто вызываются - эффективнее ставить метатаблицу с __index.
Но это уже "низкоуровневые оптимизации", а тебе я советую изучить метатаблицы, отличная штука : )
Elias
Да, что-то я забыл о том, как нормально реализовывать ООП после долгого использования библиотеки для этого. :D
Sergey
а какую либу используешь?
Elias
https://github.com/kikito/middleclass
Elias
Если кто-то раньше не встречал профиль этого парня, советую посмотреть на другие репозитории и его сайт. Тонны годноты.
Snusmumriken
ClassFoo = {}
ClassFoo.__index = ClassFoo
function ClassFoo:new(a, b, c)
local o = {}
o.a, o.b, o.c = a, b, c
return setmetatable(o, self)
end
function ClassFoo:plusTwo()
self.a = self.a + 2
self.b = self.b + 2
self.c = self.c + 2
end
obj = Class:new(10, 20, 30)
obj:plusTwo()
ClassBar = setmetatable({}, {__index = ClassFoo})
...
Snusmumriken
Ну типа для такой мелочи как ООП - либы не нужны.
Snusmumriken
Ок. Вот тебе самая короткая реализация ООП с наследованием.
Куча магии которая пашет.
function Class(name, parent)
local smt, gmt = setmetatable, getmetatable
local parent = parent
local mt, cl = {}, {}
mt.__index = type(parent) == 'table' and parent or parent and error('Class inheritance error: table expected got '..type(parent), 2) or nil
mt.__call = function(self, ...) return self.init and self.init(self, ...) or {} end -- average call method
cl.__name = name or ('class id: %8d'):format(math.random(99999999)) -- name of class for getting
cl.__index = cl
cl.Inst = function(t) return smt(t, cl) end
cl.Super = mt.__index
cl.Type = function(self, obj) return type(obj) == 'table' and gmt(obj) == gmt(self) or self.__name end
cl.IsObjectOf = function(self, class) return rawequal(class, gmt(self)) end
return smt(cl, mt)
end
Elias
Ага
Просто у меня в игре и наследование есть, и статические переменные, что несколько усложняет всё
К тому же хорошо скрывать детали реализации классов и писать в итоге только
local SomeClass = class('SomeClass')
Snusmumriken
А вот это ты зря, со статическими переменными : )
Попробуй древовидные архитектуры наследования.
А если класс - вспомогательный к чему-то - давать ему ссылку на объект, которому он помогает.
Alexey
Главная проблема при наследовании с приватными данными/методами
Что если базовый класс имеет параметр _data и наследуемый класс также определит тот же
Это пожно реализовать только через замыкания
Snusmumriken
Например, тут - ссылка на world, в котором танчик живёт.
Snusmumriken
Зачем нужна приватность?
Объективные причины, а не "ну типа кто-то узнает как оно на самом деле устроено".
Snusmumriken
Замыкания (и уж тем более - приватность через них) - в 99% случаев избыточная штукенция, которая только жрёт лишнюю память/требует лишнее процессорное время. Ну, это на моей практике.
Elias
Статические переменные мне нужны, когда в другой части программы кто-то её хочет прочитать.
Например, Person.MaxAgeAllowed или что-то типа такого
Для приватности использую переменные с подчеркиванием в начале и не использую их потом. :D
Alexey
Когда количество родителей в цепочке больше 4-5 и каждый из них имеет какие то методы/данные.
Очень неприятно когда вдруг понимаешь что вдруг переопределтил какой-то приватный метод :)
Alexey
так при наследовании в новом классе тоже нужны закрытые данные
И класс родителя могу писать не я, а взять из сторонней библиотеки
Sergey
Sergey
я у него активно inspect использую ))
Snusmumriken
Ну карочи дурацкая затея, имхо. Потом, чтобы разобраться что к чему, приходится вот такое рисовать, и то, не очень помогает, ибо тут только малая доля всего. Это ещё без множественного наследования.
Snusmumriken
Так что если наследуетесь больше двух раз - уже что-то не то, и лучше уж базовый класс изменить.
Elias
inspect - очень полезная штука для дебага, даа :)
Tverd
Alexey
Приватные методы/поля которые нельзя изменить/прочитать в наследуемом классе достаточно необходимая вещь
Alexey
C++ overload vs override
Alexey
и правила видимости для членов классов
Snusmumriken
"Достаточно необходимая" - это фигня, я хотел конкретных примеров с доказательством, почему имеенно так надо, а не иначе.
Ну и, желательно, примеров, где НЕОБХОДИМО использовать цепочки из более чем трёх наследований.
Tverd
как говорил сам Роберто, хотите приватных методов - делайте локальные функции в модуле
Snusmumriken
Нене, тут имеются ввиду приватные поля, например:
ClassFoo = {}
ClassFoo.__index = ClassFoo
function ClassFoo:new(a, b, c)
local o = {}
local private = {}
o.a, o.b, o.c = a, b, c
function o.getPrivate(key)
return private[key]
end
function o.setPrivate(key, value)
private[key] = value
end
return setmetatable(o, self)
end
И типа табличка private - "скрыта от глаз", вся фигня, и только парой методов его можно достать.
Но я всё ещё не вижу объективной необходимости так делать :<
Складывается впечатление, будто программисты - параноики, которые такие:
"Ха! Он больше не узнает что это за метод даже если попробует пройтись по всем полям таблицы! Какой я молодец, скрыл реализацию! Больше никто-о-о-о-о не узнает как оно работает!".
Ну ёпт, пользователь либы в любом случае найдёт способ всё сломать.
Пущай читает доки, там написано как использовать.
Snusmumriken
Tverd
Понятно что можно и так, я говорил про то, что Роберто в книге написал. Типа пользуйтесь вот так.
Snusmumriken
Угу : )
Благо логично и достаточно просто.
Ixtis
https://mihacooper.github.io/effil/lua/2017/09/28/effil/
Anonymous
а чем это лучше coroutines?
Ixtis
Самому интересно
Snusmumriken
Это похоже на настоящие потоки с расшаренными таблицами.
vvzvlad
а как мне получить данные внутри программы, если я хочу сделать echo "test" | program.lua?
Snusmumriken
Смотря в какой период исполнения.
Как именно запускаешь?
Что происходит при выполнении команды
'echo "text" | program.lua'?
Snusmumriken
Потому что ты можешь сделать, например, логирование, которое сбросит абсолютно всё что тебя интересует в файлик.
Или ты можешь влепить debug.debug() в нужную точку, и вывести то что нужно самостоятельно ручками, поставив программу "на паузу" (продолжить исполнение - cont).
Elias
Что-то типа того, нет?
#/bin/usr/lua
local args = { ... }
Snusmumriken
Там уже есть табличка arg со всем, что передали при запуске.
vvzvlad
не
vvzvlad
Я хотел получить данные через linux pipe. Вот так работает:
for line in io.lines() do
result = line
end
vvzvlad
echo "text" у меня выдает в stdout некие данные, а я хотел их получить в скрипте lua
Snusmumriken
Для linux pipe подключай posix.
vvzvlad
да зачем, у меня уже работает через io.lines()
Snusmumriken
Ок.
Тогда делай print.
Anonymous
тогда делай print ⓒ