Lua错误没有传递boolean

发布于 2024-09-10 02:36:50 字数 1307 浏览 3 评论 0原文

这有效...

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 。给定的变量是在上一行中检索的。应用程序运行时出现的错误是:

在 Lua API 中调用时出现不受保护的错误(脚本路径...:未将布尔值传递给 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,它将返回没有传递布尔值。我刚刚删除了布尔文字的错误检查,因为人们(包括我)通常依赖于不是布尔文字的参数被正确地视为布尔值。

This works...

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

-
These don't...

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

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

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

The otherObj test just evaluates to whether otherObj is nil or not. The variables given are retrieved in a previous line. The error I get when the application runs is:

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

SetNoClip is a function in the application that grabs the argument pushed onto the lua stack via lua_toboolean.

So why does the first work and the second and third return errors?

EDIT:

SetNoClip had this definition.

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;
}

The problem is that lua_isboolean doesn't do any implicit type conversion (but lua_toboolean does) and will only return true for literal boolean values. So if it sees nil, it will return that a boolean wasn't passed. I just removed the error check for a boolean literal, since people (including me) commonly rely on arguments that aren't boolean literals being treated correctly as booleans.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

以歌曲疗慰 2024-09-17 02:36:50

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

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

因此,A 或(B 和 C) 理论上可以返回以下任意值:

  • A 如果 A 被认为是 true 值
  • B 如果 B 是一个被视为 false 的值,并且 A 被视为 false
  • C 如果上述情况均不是,

请注意 ABC 不需要是实际的布尔值 - 只是可以解释为布尔值的值。由于 nil 被视为假值,因此您可能会遇到第二种情况,并且传递给 SetNoClip 的参数是 nil truefalse

解决此问题的一种选择是显式与 nil 进行比较,而不是仅使用对象:

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

因为 ~= 运算符保证返回布尔值。

The and operator returns its first argument if that value is something considered non-true, and its second argument otherwise.

The or operator returns its first argument if it is something considered true, and its second argument otherwise.

Thus, A or (B and C) can theoretically return any of the following:

  • A if A is a value considered true
  • B if B is a value considered false and A is considered false
  • C if neither of the above is the case

Note that A, B, and C are not required to be actual boolean values - only things that can be interpreted as booleans. Since nil is considered a false value, it's possible that the second case is occurring for you, and the argument being passed to SetNoClip is nil instead of true or false.

One option to fix this would be to explicitly compare with nil, instead of just using the object:

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

since the ~= operator is guaranteed to return a boolean.

作妖 2024-09-17 02:36:50

正如您所看到的,在 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;
}

As you have seen, any object can have a boolean interpretation in Lua. Because of this, your implementation of LuaSetNoClip is not true to the spirit & practice of Lua if you expect just a boolean object to be passed. You should use lua_toboolean directly.

I think the only argument check you can reasonably do is luaL_checkany:

int GameObject::LuaSetNoClip( lua_State *L ) {
  luaL_checkany(L, 1);
  m_noClip = lua_toboolean( L, 1 );
  return 0;
}
甜味超标? 2024-09-17 02:36:50

这取决于 SetNoClip 内部发生的情况(即,这通常不一定会导致问题)。但是,我很确定问题是 andor 返回两侧的值,而不是评估为 true。换句话说,

foo and bar

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

在您的情况下,原始代码将 truefalse 传递给 SetNoClip,而在其他示例中,您要么传递 "water",要么传递布尔值设置为 SetNoClip。 SetNoClip 可能被绳子卡住了。

It depends on what goes on inside SetNoClip (i.e. this won't necessarily cause problems in general). However, I'm pretty sure the problem is that and and or return the values on either side rather than evaluating to true or false. In other words,

foo and bar

will return foo if foo is either nil or false, otherwise it will return bar.

In your case, the original code passes true or false to SetNoClip whereas in the other examples you're either passing "water", or a boolean to SetNoClip. SetNoClip might be choking on the string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文