Lua - 太多的 C 级别(限制为 200)

最近我遇到了一个错误:“太多的 C 级别(限制为 200)”。

它到底是什么意思,我该如何防止它发生?

我以为它与循环要求有关,但它指向我的代码中创建一个新实例的行,像这样:

Class:new()

至于我的模块,我确实有一些循环要求,但我尝试通过将外部类移动到相同的模块中来修复它们,就像这样:

Class.SubClass = Class:new()

有什么想法吗?

更新:

这是我遇到的一个例子:

Class.lua

local Class = {}

function Class:new(o)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    return o
end

return Class

classes/Entity.lua

local Class = require('Class')
local Player = require( 'classes/Player')

local Entity = Class:new()

function Entity:getPlayer()
    return Player:new()
end

return Entity

classes/Player.lua

local Class = require('Class')
local Entity = require('classes/Entity')

local Player = Class:new()

function Player:getEntities()
    local entities = {}
    for i = 1, 100 do
        entities[i] = Entity:new()
    end
    return entities
end

return Player

我意识到这是一个循环依赖,但我找到的唯一解决方案是:Lua:如何避免循环要求,使用全局变量。有没有办法用本地变量避免这个问题?

点赞
用户79125
用户79125

首先,我会仔细检查 Entity:getPlayer 为什么需要存在以及为什么会创建一个新的 player。(即使这只是示例代码,为什么 entity 要依赖于 player,而不是反过来?)

让我们来看几种不使用全局变量来解决这个问题的方法。

TL;DR:请参考“模块分离”解决方案。

运行时导入

这是 @Egor 的解决方案。它将模块导入从文件加载时间移动到运行时。这会稍微隐藏一些依赖,但这只是为了解决一个 require 循环的最小改变。

classes/Entity.lua

local Class = require('Class')
local Player

local Entity = Class:new()

function Entity:getPlayer()
    Player = Player or require('classes/Player')
    return Player:new()
end

return Entity

数据注入

将 player 传递给需要它的 entities。

classes/Entity.lua

local Class = require('Class')
local Player = require('classes/Player')

local Entity = Class:new()

function Entity:init(player_class)
    self.player_class = player_class
end

function Entity:getPlayer()
    return self.player_class:new()
end

return Entity

classes/Player.lua

local Class = require('Class')
local Entity = require('classes/Entity')

local Player = Class:new()

function Player:getEntities()
    local entities = {}
    for i = 1, 100 do
        -- 或者,我们可以传递相关的 player 实例 (self)。
        entities[i] = Entity:new(Player)
    end
    return entities
end

return Player

逻辑注入

我不喜欢这种解决方案,因为它需要你 始终以相同的路径 导入 entity.lua。如果有时候使用 require('classes/Entity'),有时候使用 require('classes.Entity'),Lua 模块可能有不同的定义。这可能是部分类的一个好模式,但这并不像你所做的那样。不管怎样,出于完整性的考虑,仍然列出来。

如果你有一个全局的 Entity 或拥有它的另一个模块,你可以在那里注入以解决路径的风险。

classes/Player.lua

local Class = require('Class')
local Entity = require('classes/Entity')

local Player = Class:new()

...

-- 向被导入模块添加功能。
function Entity:getPlayer()
    return Player:new()
end

return Player

模块分离

_这是其中一个最干净的解决方案_。当你有两个相互依赖的事物时,使它们独立起来,并将依赖项移动到更高的模块中。但是,它也是最远离你当前代码的方案之一。很可能你会像使用全局变量一样使用 Population 的实例,但并没有要求它必须是全局的。

classes/Population.lua

local Class = require('Class')
local Entity = require('classes/Entity')
local Player = require('classes/Player')

local Population = Class:new()

function Population:getPlayer()
    return Player:new()
end

function Population:getEntities()
    local entities = {}
    for i = 1, 100 do
        entities[i] = Entity:new()
    end
    return entities
end

return Population
2022-03-10 19:13:29
用户17165477
用户17165477

我只知道如何解决那个问题

太多的 C 级别 (限制是 200)

这个问题是由于头文件彼此包含所导致的,例如 A 要求 B & B 要求 A。

希望这对你有用 :)

2022-05-31 07:13:18