Lua错误未通过布尔值。

3

这个功能可以正常运作...

if ( tileType == "water" or 
  ( otherObj and otherObj:GetType() == "IceBlock" )) then
  self:SetNoClip( true )
else
  self:SetNoClip( false )
end

- 这些不会影响您的网站

self:SetNoClip( tileType == "water" or 
  ( otherObj and otherObj:GetType() == "IceBlock" ))

//----------------------------------------------------------

local noClip = ( tileType == "water" or 
  ( otherObj and otherObj:GetType == "IceBlock" ))
self:SetNoClip( noClip )
otherObj测试只是判断otherObj是否为nil。给定的变量是在之前的一行中检索的。当应用程序运行时,我收到以下错误:

unprotected error to call in Lua API(script path...: Did not pass boolean to SetNoClip).

SetNoClip是应用程序中的一个函数,通过lua_toboolean从lua堆栈中获取推送的参数。

那么为什么第一个可以正常工作,而第二个和第三个会返回错误?

编辑:

SetNoClip曾经有这个定义。

int GameObject::LuaSetNoClip( lua_State *L ) {
  if ( !lua_isboolean( L, -1 )) {
    LogLuaErr( "Did not pass boolean to SetNoClip for GameObject: " + m_type );
    return luaL_error( L, "Did not pass boolean to SetNoClip" );
  }
  m_noClip = lua_toboolean( L, -1 );
  return 0;
}

问题在于lua_isboolean不进行任何隐式类型转换(但lua_toboolean会),并且仅对字面布尔值返回true。因此,如果它看到nil,它将返回未传递布尔值的错误。我刚刚删除了对布尔字面量的错误检查,因为人们(包括我)通常依赖于非布尔字面量参数被正确地视为布尔值。

1
就算是对你不起作用的,错误信息也不只是胡言乱语。每当你遇到错误时,将错误信息发布出来总是很有帮助的。通常它们会告诉你问题出在哪里以及具体是什么问题。我们很乐意帮助你解读它们,这样下一次你就可以充分利用它们了。 - Cogwheel
我确实发布了它。它不是胡言乱语。它非常清楚问题所在。没有将布尔值传递给SetNoClip函数。 - random
哦,抱歉我错过了><需要更多的咖啡因(还有点赞我的人:P)。我让它更加突出了一些... - Cogwheel
就我所知,这似乎与Lua的惯用法相反。通常,“布尔”函数应该接受任何输入并“考虑”其真实性,而不是直接与truefalse进行比较。我会对这个API感到恼火... - Cogwheel
3个回答

1

正如你所见,Lua中的任何对象都可以有一个布尔解释。因此,如果你期望只传递一个布尔对象,那么你对LuaSetNoClip的实现就不符合Lua的精神和实践。你应该直接使用lua_toboolean

我认为你可以合理地进行唯一的参数检查,即luaL_checkany

int GameObject::LuaSetNoClip( lua_State *L ) {
  luaL_checkany(L, 1);
  m_noClip = lua_toboolean( L, 1 );
  return 0;
}

是的,函数确实被改变了,注意编辑中提到“had”这个定义的部分。 - random

1

and 运算符如果其第一个参数是被认为是非真的值,则返回该值,否则返回其第二个参数。

or 运算符如果其第一个参数是被认为是真的值,则返回该值,否则返回其第二个参数。

因此,A or (B and C) 理论上可以返回以下任何一种情况:

  • 如果 A 是被认为是真的值,则返回 A
  • 如果 B 是被认为是假的值且 A 被认为是假的值,则返回 B
  • 如果以上两种情况都不是,则返回 C

请注意,ABC 不必是实际的布尔值 - 只要是可以被解释为布尔值的东西即可。由于 nil 被认为是假值,所以可能发生了第二种情况,传递给 SetNoClip 的参数是 nil 而不是 truefalse

修复此问题的一种方法是明确与 nil 进行比较,而不仅仅使用对象:

( otherObj ~= nil and otherObj:GetType() == "IceBlock" )

由于~=运算符保证返回一个布尔值。


谢谢,这正是我需要知道的。然而,这并没有解释为什么它在 if 条件语句中仍被评估为布尔值。if 语句是否进行隐式类型转换,而参数传递则不进行类型转换(例如,if(nil)将 nil 转换为 false,但 SetNoClip(nil)不会)。 - random
因为这就是 if 的设计原理。当我们说“被认为是真”和“被认为是假”时,if 就是其中之一在进行判断。除了 falsenil 以外,所有的值都被认为是 true - Cogwheel
是的,但为什么不将其应用于传递函数参数呢?如果函数期望布尔值,并接收到nil,您会认为它会将其转换为false,就像条件语句设计的那样。这是有原因的吗? - random
在我看来,这是函数的设计缺陷。期望布尔值的函数应该像 if 一样处理值。 - Cogwheel
好的,SetNoClip使用了lua_toboolean。文档表示...将给定可接受索引处的Lua值转换为C布尔值(0或1)。与Lua中所有测试一样,lua_toboolean对于除false和nil之外的任何Lua值都返回1;否则它将返回0。当使用非有效索引调用时,它还返回0。(如果您想仅接受实际布尔值,请使用lua_isboolean来测试该值的类型。)因此,在调用lua_toboolean时,应将nil评估为false。这里有什么问题?附言:必须取消答案。不起作用。(在测试之前未保存文件)。 - random
将此设置为答案,因为它击中了问题的主要点,但其中一部分是无法从我提供的信息中解决的(不幸的是)。在编辑中发布更多信息。 - random

0

这取决于SetNoClip内部发生了什么(即一般情况下不一定会引起问题)。但是,我相当确定问题在于andor返回两侧的值而不是评估为truefalse。换句话说,

foo and bar

如果foonilfalse,则返回foo,否则返回bar

在您的情况下,原始代码将truefalse传递给SetNoClip,而在其他示例中,您要么传递"water",要么传递布尔值给SetNoClip。SetNoClip可能无法处理字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接