【读书笔记】语言特性-元表和元方法 练习(三)

练习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,已实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值