Zer0Galaxy 2 187 Опубликовано: 23 июня, 2015 Приз - компьютер или робот любой комплектации (кроме креатива) тому, кто реализует readonly-поле объекта через переопределение оператора присваивания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Totoro 3 562 Опубликовано: 23 июня, 2015 Метатаблицы Карл... Как ты это сделаешь для "примитивных" типов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Krutoy 1 169 Опубликовано: 23 июня, 2015 Приз - компьютер или робот любой комплектации (кроме креатива) тому, кто реализует readonly-поле объекта через переопределение оператора присваивания. Всё уже реализовано. Вот тут например вообще можно устанавливать свои функции для get и set переменной. Как ты это сделаешь для "примитивных" типов? Можно можно. Даже цифры, и даже нил. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Totoro 3 562 Опубликовано: 23 июня, 2015 Можно можно. Даже цифры, и даже нил. Узнаю Луа. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Ktlo Автор темы 789 Опубликовано: 23 июня, 2015 Можно) переопределить оператор присваивания Метатаблицы Карл... Я почитал про метатаблицы поподробнее и всё исправил. Оказывается запретить изменение ключей можно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
swg2you 403 Опубликовано: 23 июня, 2015 (изменено) ro = {a=1, b=2} obj = {b=3, c=4} setmetatable(obj,{__index=ro,__newindex=function(_,_,_)end}) prn(obj.a, obj.b, obj.c) -->1 3 4 (значение obj.b=3 установленное до объявления метаметодов перекрывает ro.b=2, и __index=ro не вызывается. obj.a=5 obj.b=6 obj.c=7 prn(obj.a, obj.b, obj.c) -->1 6 7 (obj.a=5 выполнил function(_,_,_)end ничего не сделав) Эта строка setmetatable(obj, {__index=ro, __newindex=function(_,_,_)end}) говорит следующее: Для несуществующих индексов таблицы obj, читать значения из ro, а при попытке записи выполнять ничего - function(_,_,_)end Или так: setmetatable(obj,{__index=ro,__newindex=function(t,k,v) print('Иди в пень! '..k..' ' - ридонли!') end}) --===-- При попытке добавления нового значения (например obj.d=8) выполнится ничего и значение добавлено не будет. Чтобы мы могли добавлять новые индексы в obj нужно в нашем ничего проверять, есть ли добавляемый индекс в ro, и если такого индекса нет, то добавлять его в obj. Это можно сделать так: setmetatable(obj, {__index=ro,__newindex=function(t,k,v) local _=rawget(ro,k) or rawset(t,k,v) end}) При попытке записи obj.d=8, наше ничего, сделает: если не ro.k то rawset(t,k,v) наплевав на всякие там метаметамета. Теперь мы можем: ro = {a=1, b=2} obj = {b=3, c=4} setmetatable(obj,{__index=ro,__newindex=function(t,k,v) local _=rawget(ro,k) or rawset(t,k,v) end}) prn(obj.a, obj.b, obj.c, obj.d) obj.a=5 obj.b=6 obj.c=7 obj.d=8 prn(obj.a, obj.b, obj.c, obj.d) upd:Прочел следующие посты и понял, как я далек от объектно-ориентированного програмирования ) Изменено 23 июня, 2015 пользователем swg2you Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 23 июня, 2015 (изменено) Уже ближе. Вот пример реализации класса с двумя обычными полями (c,d) и двумя readonly-полями (a,b) Class={a=1, b=2, __newindex=function()end} Class.__index=Class function Class:new() local obj={c=3, d=4} setmetatable(obj,self) return obj end function Class:ShowFields() print(self.a, self.b, self.c, self.d) end function Class:SetA(Val) Class.a=Val end function Class:SetB(Val) Class.b=Val end obj = Class:new() obj:ShowFields() obj.a=5 obj.b=6 obj.c=7 obj.d=8 obj:ShowFields() obj:SetA(5) obj:SetB(6) obj:ShowFields() RO-поля можно менять при помощи методов класса. Одна проблема - RO-поля общие для всех экземпляров класса И можно ли будет от такого класса сделать наследника если невозможно добавлять новые поля? Изменено 23 июня, 2015 пользователем Zer0Galaxy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Ktlo Автор темы 789 Опубликовано: 23 июня, 2015 И можно ли будет от такого класса сделать наследника если невозможно добавлять новые поля? Можно: function newClass() local object, private = class() setmetatable(object, {}) --Удаляем метатаблицу object.foo(...) --Добавляем метод --<Что-нибудь> end setmetatable(object, private) --Возвращаем нашу метатаблицу назад return object, private end Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 23 июня, 2015 При попытке добавления нового значения (например obj.d=8) выполнится ничего и значение добавлено не будет. Чтобы мы могли добавлять новые индексы в obj нужно в нашем ничего проверять, есть ли добавляемый индекс в ro, и если такого индекса нет, то добавлять его в obj. Это можно сделать так: setmetatable(obj, {__index=ro,__newindex=function(t,k,v) local _=rawget(ro,k) or rawset(t,k,v) end}) При попытке записи obj.d=8, наше ничего, сделает если не ro.k то rawset(t,k,v) наплевав на всякие там метаметамета. Так, а как сделать что бы таблица ro была не одна на всех, а своя для каждого экземпляра класса? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
swg2you 403 Опубликовано: 23 июня, 2015 (изменено) Так, а как сделать что бы таблица ro была не одна на всех, а своя для каждого экземпляра класса?Я далек от ООП, но думаю, что как-то так.setmetatable(obj1, {__index=ro1,__newindex=function(t,k,v) local _=rawget(ro1,k) or rawset(t,k,v) end}) setmetatable(obj2, {__index=ro2,__newindex=function(t,k,v) local _=rawget(ro2,k) or rawset(t,k,v) end}) Или по твоему коду: Class={a=1, b=2} function Class:new() local obj={c=3, d=4} local nc={} for k,v in pairs(self) do nc[k]=v end setmetatable(obj,{__index=nc,__newindex=function(t,k,v) local _=rawget(nc,k) or rawset(t,k,v) end}) return obj end function Class:ShowFields() prn(self.a, self.b, self.c, self.d) end function Class:SetA(Val) rawset(self,'a',Val) end function Class:SetB(Val) rawset(self,'b',Val) end obj = Class:new() obj2 = Class:new() obj:ShowFields() obj.a=5 obj.b=6 obj.c=7 obj.d=8 obj:ShowFields() obj:SetA(5) obj:SetB(6) obj:ShowFields() obj2:ShowFields() Если я правильно понял, что тебе от этого кода нужно. Изменено 23 июня, 2015 пользователем swg2you Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 24 июня, 2015 Приз за решение проблемы ReadOnly-полей уходит к swg2you. Жду комплектацию компьютера и адрес куда его отправлять. Хотелось бы узнать про параметры (t,k,v) функции __newindex. А про функции rawget и rawset поподробнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
swg2you 403 Опубликовано: 24 июня, 2015 Приз за решение проблемы ReadOnly-полей уходит к swg2you. Жду комплектацию компьютера и адрес куда его отправлять. Хотелось бы узнать про параметры (t,k,v) функции __newindex. А про функции rawget и rawset поподробнее. __newindex(t,k,v) - (новый индекс) вызовется если в таблицу t, несуществующему ключу k присвоить значение v v=rawget(t,k) и rawset(t,k,v) - позволяют получить/присвоить значение v напрямую, игнорируя всякие метаметоды Приз за решение проблемы прошу передать в международный фонд помощи мадагаскарским хомячкам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 24 июня, 2015 Компьютер наилучшей комплектации отправлен на Мадагаскар хомячкам до востребования. А какие еще интересные функции кроме __index и __newindex могут содержать метатаблицы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
LeshaInc 624 Опубликовано: 24 июня, 2015 Компьютер наилучшей комплектации отправлен на Мадагаскар хомячкам до востребования. А какие еще интересные функции кроме __index и __newindex могут содержать метатаблицы? Почитай это. http://xgm.guru/p/love2d/112958 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 24 июня, 2015 http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/ тоже интересная статейка, но на инглише Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
swg2you 403 Опубликовано: 24 июня, 2015 (изменено) Компьютер наилучшей комплектации отправлен на Мадагаскар хомячкам до востребования. А какие еще интересные функции кроме __index и __newindex могут содержать метатаблицы? Первоисточник всего: http://www.lua.org/manual/5.2/manual.html#2.4 Изменено 24 июня, 2015 пользователем swg2you Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
kaka888 10 Опубликовано: 14 января, 2019 10.06.2015 в 10:35, LeshaInc сказал: Любой программист это прочитает. Лол, реально со второй строки автоматом стало читаться :DDD Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
MrAbad 12 Опубликовано: 22 декабря, 2019 Я уже пару лет периодически читаю этот тред, и меня мучает вопрос, почему, нельзя просто произвести инкапсуляцию сокрытие для Рид-онли переменных, мой вариант: function Class1() local self = { ["var1"] = "Nothing" } local private = { ["var1"] = "Secret!" } function self.getVar1() print(self.var1) end function self.getPrivateVar1() return private.var1 end return self end В файле класса, и: require("class1") local myObject = Class1() print(myObject.getPrivateVar1()) --> Secret! в файле программы. По-идее к этой переменной никак не получить доступ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 23 декабря, 2019 11 час назад, MrAbad сказал: По-идее к этой переменной никак не получить доступ Можно конечно и так, но у такого способа есть маленький недостаток. Для каждого рид-онли поля каждого экземпляра объекта необходимо создавать отдельную функцию. В твоем примере, если я создам несколько экземпляров Class1: require("class1") local myObjects={} for i=1,1000000 do myObjects[i]=Class1() end будет создано соответствующее количество не только таблиц private но и функций getPrivateVar1. Каждая такая функция будет занимать место в небезграничном ОЗУ, хотя все они выполняют одно и тоже действие. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
MrAbad 12 Опубликовано: 3 апреля, 2020 В 23.12.2019 в 12:25, Zer0Galaxy сказал: Для каждого рид-онли поля каждого экземпляра объекта необходимо создавать отдельную функцию. Хорошо, можно так: ("MyClosure.lua") function MyClosure(a, b) self = {} readOnly = { var1 = true } self.a = a self.b = b function self.printAandB() print(self.a, self.b) end function self.GET(var) return readOnly[var] end return self end ("main.lua") require("MyClosure") local obj1 = MyClosure(3,14) obj1.printAandB() --> 3 14 print(obj1.GET("var1")) --> true Кстати, я не даром назвал файл "MyClosure", потому что, это не ООП, а в чистом виде замыкание и функциональное программирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах