练习1:请定义一个元方法__sub,该元方法用于计算两个集合的差集(集合a-b是位于集合a但不位于集合b的元素)
Set = {}
-- 并集
function Set.union(a, b)
local res = Set.new{}
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
-- 交集
function Set.intersection(a, b)
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k] -- 如 b[k]不存在,则b[k]为nil, res[k] = nil 意味着删除 该元素,所以 res[k]只会保存 true
end
return res
end
function Set.sub(a,b)
local res = Set.new{} -- 给一个空表做参,返回有元表的空表
for k in pairs(a) do -- {1,2,3,4} {3,4,5,6}
if not b[k] then
res[k] = true
end
end
for k in pairs(b) do
if not a[k] then
res[k] = true
end
end
return res
end
function Set.length(set)
local count = 0
for i in pairs(set)
count = count + 1
end
return count
end
function Set.tostring(set)
local l = {}
for e in pairs(set) do -- 循环set表
l[#l + 1] = tostring(e)
end
return "{" .. table.concat(l, ", ") .. "}" -- table.concat(l, ", ") 把 L表中各元素用,号隔开
end
local mt = {}
function Set.new(l)
local set = {}
setmetatable(set, mt)
mt.__sub = Set.sub
mt._len = Set.length
for _, v in ipairs(l) do set[v] = true end
return set
end
s1 = Set.new{1,2,3,4}
s2 = Set.new{3,4,5,6}
s3 = s1 - s2
print(Set.tostring(s3))
s4 = Set.new{1,2,3}
print(#s4)
练习2. 请定义一个元方法__len, 该元方法用于实现使用#s计算集合s中的元素个数
答:练习1的 s4 已实现
练习3. 实现只读表的另外一种方式是将一个函数用作__index元方法。这种方式使用访问的开销更大,但是创建只读表的开销更小(因为所有的只读表能够共享同一个元表)。
请使用这种方式重写函数readOnly
local proxy={}
local mt={}
function readOnly(t)
mt.__index=function (_,k) return rawget(t,k) end
mt.__newindex=function (t,k,v) error("attempt to update a read-only table",2) end
setmetatable(proxy,mt)
return proxy
end
days={"Sunday","Monday","Tuesday","Wednesday","Tursday","Friday","Saturday"}
days=readOnly(days)
print(days[1])
--days[2]="Noday"
test=readOnly{1,2,3,4}
print(test[1])
test[2]=4 -- 这句会报错,因为 调用了rawget(),找不到 __index元方法,从而实现只读的表
练习 4 代理表可以表示除表外的其它类型的对象 请编写一个函数 fileAsArray该函数以一个文件名为参数,返回 值为 对应文件的代理理,当执行 =fileAsArray( "myFile ”) 后,访问 t[i ]返回指定文件的第 个字节, t[i]的赋值更新第i个字节
function fileAsArray(filename)
local proxy={}
local filearray={}
local file=assert(io.open(filename,"r"))
for block in file:lines(1) do
filearray[#filearray+1]=block
end
file:close()
local mt={
__index=function (_,k) return filearray[k] end,
__newindex=function (_,k,v)
filearray[k]=v
local file=assert(io.open(filename,"w"))
for _,w in ipairs(filearray) do
file:write(w)
end
file:close()
end,
__pairs=function ()
return function (_,k)
local nextkey,nextvalue=next(filearray,k)
return nextkey,nextvalue
end
end,
__len=function ()
return #filearray
end
}
setmetatable(proxy,mt)
return proxy
end
--the content under the line are for test
f=fileAsArray("text")
print(f[2])
f[2]="i"
for x,y in pairs(f) do
print(x,y)
end
print(#f)
练习·5: 扩展之前的示例,使得我们能够使用 pairs(t)遍历一个文件中的所有字节,并使用#t来获得文件大小
练习4,已实现