Lua:类方法跳过第一个参数

时间:2017-07-23 13:59:28

标签: oop lua torch

我正在尝试在Lua中实现一个应该被实例化的类。但是,我收到一个错误,其中函数BatchLoader.init的输入参数被移位。我是否缺少将self关键字作为参数输入到任何成员函数(如python),或者类定义是否还有其他错误?

整个类代码看起来像这样(我删除了不重要的东西):

function BatchLoader:new()
    setmetatable({}, BatchLoader)
    self.epoch_done = false
    return self
end

function BatchLoader:init(X, y, sids, batch_size, argshuffle)    
    print("In batchloader")
    print(X:size())    -- Prints size(62000, 1) [which is 'y']
    print(y:size())    -- Prints size(62000, 1) [which is 'sids']
    print(sids)        -- Prints '10'           [which is 'batch_size']
end

但是当我创建这个类,然后调用函数BatchLoader.init时,似乎y被解释为X,y被解释为sids等等。因此,batch_size的输入被解释为sids,每个参数都与实际参数“移开”。

以下代码是我在进入BatchLoader.init之前调用的代码。这里的所有内容都按预期打印。

local BatchLoader = require "../datahandler/BatchLoader.lua"
local trainLoader = BatchLoader:new()
print(X_data[{{1, 62000}, {}, {}}]:size()) -- Prints size(62000, 8, 16)
print(y_data[{{1, 62000}, {}}]:size())     -- Prints size(62000, 1)
print(sid_data[{{1, 62000}, {}}]:size())   -- Prints size(62000, 1)

local X_train, y_train, sid_train = trainLoader.init(
    X_data[{{1, a}, {}, {}}],
    y_data[{{1, a}, {}}],
    sid_data[{{1, a}, {}}],
    10, true)

我的问题是:那里的阶级宣言有什么问题吗?这是我在Lua的第一个OOP代码,所以任何想法或帮助都表示赞赏! :)

2 个答案:

答案 0 :(得分:4)

在Lua中,这种语法:

data AppM a = AppM {unwrapAppM :: ReaderT Env (LoggingT IO) a}

instance Functor AppM where
  fmap fn appm = AppM $ fmap fn (unwrapAppM appm)


instance Applicative AppM where
  pure a = AppM $ pure a

是这个的语法糖:

o:f(x, y)

定义和调用都是如此。在这里,您使用冒号语法定义o.f(self, x, y) 并使用点语法调用它,因此它将无法工作,因为第一个参数将变为init而其他参数将被一个参数关闭。解决方案是像这样调用self

init

这解决了这个问题,但请注意,在您的示例中,构造函数也完全被破坏。因为您使用冒号语法定义它,它将始终返回local X_train, y_train, sid_train = trainLoader:init( X_data[{{1, a}, {}, {}}], y_data[{{1, a}, {}}], sid_data[{{1, a}, {}}], 10, true) 表本身而不是新实例。由于它是一个类方法,您应该编写它并使用点语法调用它:

BatchLoader

或简单地说:

function BatchLoader.new()
    local self = setmetatable({}, BatchLoader)
    self.epoch_done = false
    return self
end

然后你也用点语法调用它:

function BatchLoader.new()
    return setmetatable({epoch_done = false}, BatchLoader)
end

要了解这些内容,如果您尚未完成,我强烈建议您购买最新版本的Lua编程副本,并阅读面向对象编程一节。

答案 1 :(得分:3)

方法语法(使用foo:bar代替foo.bar)会自动引入self参数。

在功能定义上,function Foo:bar( ... )相当于function Foo.bar( self, ... )。在函数调用中,foo:bar( ... )大致相当于foo.bar( foo, ... )(后者评估foo两次)。

让我们剖析您的代码:

function BatchLoader:new()
    setmetatable({}, BatchLoader) -- creates a table & throws it away
    self.epoch_done = false       -- self is the hidden first argument
    return self
end

local trainLoader = BatchLoader:new()  -- i.e. BatchLoader.new( BatchLoader )

这意味着您有效地运行

function BatchLoader:new()
    setmetatable({}, BatchLoader)
    BatchLoader.epoch_done = false
    return BatchLoader
end

当然不是你想要的。有几种方法可以做你想要的事情

-- fixed creation scheme
function BatchLoader.new( )
   local self = { epoch_done = false }
   return setmetatable( self, BatchLoader )
end

-- acceptable uses:
local trainLoader = BatchLoader.new( )
local trainLoader = BatchLoader:new( ) -- ignores passed self

-- permit passing base object
function BatchLoader:new( )  -- equivalently: BatchLoader.new( self )
   self = self or { }  -- use passed table or create new
   self.epoch_done = false
   return setmetatable( self, BatchLoader )
end

-- acceptable uses:
local trainLoader = BatchLoader.new( )  -- creates from scratch
local trainLoader = BatchLoader.new { n = 23 } -- re-uses this table
-- WRONG uses:
local trainLoader = BatchLoader:new( )  -- reuses BatchLoader class as object

或许多其他选项。

您同样混淆了另一个电话的方法表示法:

function BatchLoader:init(X, y, sids, batch_size, argshuffle)

很好,相当于

function BatchLoader.init(self, X, y, sids, batch_size, argshuffle)

然后你错误地称之为

local X_train, y_train, sid_train = 
  trainLoader.init( X, y, ... )

(看看为什么一切都转移了?)

使用trainLoader:init( X, y, ... )trainLoader作为self传递。