Day14 用 100 寸超大萤幕写 Code 的感觉 - 用 metatable 改变预设行为

前两天我已经学会用 CC: Tweaked 电脑读取磁片和播放音乐
今天我要来写 Code 啦 !!!
.....
不是本来就在写 Code 吗?
但这次我要在麦块世界里的超大萤幕写 Code ~
来看看新的 Monitor 方块长怎样?
cctweaked-computer-monitor

.....
萤幕和电脑一比一相同大小,有点搞不清楚谁是谁 XD
这画面上方是电脑主机,下方是萤幕
跟磁碟机一样,萤幕可以接在电脑旁边任何位置
而我在电脑主机输入

monitor bottom ls

意思就是,执行 ls,但把输出重新导向到下方萤幕
我目前的位置是新电脑的根目录,所以萤幕上只显示 rom

用超大萤幕写 Code

虽然在现实世界,不会真的干这种事(要也是拿来看电影打电动啊,怎麽会拿写 Code)
但至少,我可以在麦块里面实现罗!
我发现萤幕方块是可以堆叠的,两个相邻的萤幕会自动合并成更大的萤幕!
比较可惜的是,我原本以为可以无限制堆叠(也太贪心)
但实测後得知,最多可以堆出 长8方块、高6方块的大萤幕
但以人物比例来看,应该是有 100 寸吧 XD

我在电脑上输入

monitor top edit rom/programs/monitor.lua

就形成这个画面啦!顺便找一堆村民来看我写 Code ...
cctweaked-computer-big-monitor

接下来看看 monitor.lua 在做些什麽事
首先看到这一行很陌生

local monitor = peripheral.wrap(sName)

接着再看 /rom/apis/peripheral.lua
看到一个有趣的新东西 setmetatable

function wrap(name)
    expect(1, name, "string")

    local methods = peripheral.getMethods(name)
    if not methods then
        return nil
    end

    local result = setmetatable({}, {
        __name = "peripheral",
        name = name,
        type = peripheral.getType(name),
    })
    for _, method in ipairs(methods) do
        result[method] = function(...)
            return peripheral.call(name, method, ...)
        end
    end
    return result
end

Metatable on Lua

在 Lua,每个 table 都可以自定义自己的 metatable 来改变预设的行为
预设情况下,metatable 是 nil

t = { 1, 2, 3 }
print(getmetatable(t))  -- nil

我们可以透过 setmetatable 来改变其预设的 metatable
不过在 Lua,只能改 table 的 metatable
其他型别的 metatable,据了解可以透过 C/C++ 修改
还记得之前我印出 table 时,都是得到记忆体位址吗?
改变 metatable 定义後,我们可以直接印出 table 里面所有值

t = { 1, 2, 3 }
print(getmetatable(t))  -- nil
print(t)                -- table: 0x20e6b60
setmetatable(t, {
  __tostring = function(table)  -- 改变 table 被 print 的输出
    local str = ''
    for _, value in pairs(table) do
      str = str .. value .. ','
    end
    return str
  end
})
print(t)                -- 1,2,3,

以下是一些可以透过 metatable 改变的行为,称为 metamethod
但应该不止这些,有些 metamethod 我没有深入探究

operator metamethod
+ __add
- __sub
* __mul
/ __div
- (负数) __unm
% __mod
^ (次方) __pow
== __eq
< __lt
<= __le
.. __concat

__name 可以改变预设的型别显示,虽然我看不出用途...
__len 可以改变计算元素数量的方式
__pairs 可以改变 pairs, iparis 迭代函数取值的规则
__index 改变用 key index 取值的规则
__newindex 改变新增元素的规则
__tostring 改变 table 被 print 的输出

以下是更多的范例

t1 = { 1, 2, 3 }
t2 = { 4, 5, 6 }
print(getmetatable(t1))     -- nil
print(t1)                   -- table: 0x23d87d0
mt = {
  __name = "mytable",
  __add = function(tableA, tableB)
    local result = setmetatable({}, mt) -- 这边要记得设定 metatable,这样新的 table 也仍然是自定义行为
    for i = 1, #tableA do
        table.insert(result, tableA[i])
    end
    for i = 1, #tableB do
        table.insert(result, tableB[i])
    end
    return result
  end,
  __index = function(table, key)        -- 这样这个 table 就变成存取从 0 index 开始
    return table[key + 1]
  end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
print(t1)                   -- mytable: 0x23d87d0

mt.__tostring = function(table) -- mt["__tostring"] 的语法糖
  local str = ''
  for _, value in pairs(table) do
    str = str .. value .. ','
  end
  return str
end
print(t1)                   -- 1,2,3,
print(t1 + t2)              -- 1,2,3,4,5,6,
print(t1[0])                -- 1

保护 metatable

metatable 可以做如上述这麽大幅度的行为改变
但 Lua 也提供我们方式可以保护 metatable
使用 setmetatable 设定 metatable 之後,就再也不能改变

t = { 1, 2, 3 }
mt = {
  __tostring = function(table)
    local str = ''
    for _, value in pairs(table) do
      str = str .. value .. ','
    end
    return str
  end,
  __metatable = "Access Denied"  -- 可以给任意值
}

setmetatable(t, mt)
print(t)            -- 1,2,3,
setmetatable(t, {}) -- input:15: cannot change a protected metatable

以上就是 Lua metatable 和 metamethod 的应用


<<:  Day13:Send Message To Room(发送讯息到特定房间)

>>:  [Day_15]回圈与生成式

【Day02】Verilog 基本简介

Verilog 电路基本架构 举个简单电路的例子: module adder( a, b, c );...

Rebol 语言和你 SAY HELLO!!

第十五天 各位点进来的朋友,你们好阿 小的不才只能做这个系列的文章,但还是希望分享给点进来的朋友,知...

StockAPI-错误讯息处理 (Day32)

先前我们建立的StockAPI在解析token字串时,并没有针对解析错误的情况去做错误处理,所以如果...

[Day 1] 身为一名普通 iOS 开发者所需的程序以外的知识 Intro

前言 Hi 我是一名普通的 iOS 开发者,兴趣使然的 UI 设计师。不小心参与了几年 iOS 开发...

Day12.进入 ARM 世界: ARM Cortex-M Exception Behavior

Nested Interrupts Cortex-M3 和 NVIC 在硬体架构上支援(Nested...