lua的__index提供便利的单继承功能

来源:互联网 发布:万里独行知马力 编辑:程序博客网 时间:2024/04/30 19:00

I said earlier that, when we access an absent field in a table, the result is nil. This is true, but it is not the whole truth. Actually, such access triggers the interpreter to look for an __index metamethod: If there is no such method, as usually happens, then the access results in nil; otherwise, the metamethod will provide the result.

The archetypal example here is inheritance. Suppose we want to create several tables describing windows. Each table must describe several window parameters, such as position, size, color scheme, and the like. All these parameters have default values and so we want to build window objects giving only the non-default parameters. A first alternative is to provide a constructor that fills in the absent fields. A second alternative is to arrange for the new windows to inherit any absent field from a prototype window. First, we declare the prototype and a constructor function, which creates new windows sharing a metatable:

    -- create a namespace    Window = {}    -- create the prototype with default values    Window.prototype = {x=0, y=0, width=100, height=100, }    -- create a metatable    Window.mt = {}    -- declare the constructor function    function Window.new (o)      setmetatable(o, Window.mt)      return o    end
Now, we define the __index metamethod:
    Window.mt.__index = function (table, key)      return Window.prototype[key]    end
After that code, we create a new window and query it for an absent field:
    w = Window.new{x=10, y=20}    print(w.width)    --> 100
When Lua detects that w does not have the requested field, but has a metatable with an __index field, Lua calls this __index metamethod, with arguments w (the table) and "width" (the absent key). The metamethod then indexes the prototype with the given key and returns the result.

The use of the __index metamethod for inheritance is so common that Lua provides a shortcut. Despite the name, the __index metamethod does not need to be a function: It can be a table, instead. When it is a function, Lua calls it with the table and the absent key as its arguments. When it is a table, Lua redoes the access in that table. Therefore, in our previous example, we could declare __index simply as

    Window.mt.__index = Window.prototype
Now, when Lua looks for the metatable's __index field, it finds the value of Window.prototype, which is a table. Consequently, Lua repeats the access in this table, that is, it executes the equivalent of
    Window.prototype["width"]
which gives the desired result.

原创粉丝点击