如何检查一个 Ruby 对象是否为布尔类型

154

我似乎无法轻松地检查一个对象是否为布尔值。Ruby中有类似的东西吗?

true.is_a?(Boolean)
false.is_a?(Boolean)

我现在正在做这件事情,想要缩短它:

some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))

9个回答

150

我认为这很简洁并且可以自我说明:

[true, false].include? foo

如果使用Rails或ActiveSupport,您甚至可以使用in?直接进行查询。

foo.in? [true, false]

在浮点数的情况下,我不建议检查所有可能的值,但当只有两个可能的值时是可行的!


1
目前为止最好的答案,尽管我也喜欢有人在评论中提出的 foo == true or foo == false - Ryan Taylor
6
我喜欢这个,因为它的意图不像!!foo == foo那样含糊。 - stringsn88keys
绝对符合Python风格!毫无疑问,这是迄今为止最语义化的答案。 - J.M. Janzen

147

我所能想到的最简单方法:

# checking whether foo is a boolean
!!foo == foo

6
类 X;def !; self end end ; x = X.new ; !!x == x #=> true(翻译):定义了一个 X 类和一个它的实例 x,其中类 X 定义了一个方法“!”,该方法返回对象本身。在创建了 x 实例后,通过对其两次取反(即 !!x)会得到与 x 相同的结果,因此表达式“!!x == x”为真。 - Alexey
5
是的,这被称为“鸭子类型”,是面向对象编程的核心原则之一。我认为这是一种特性。 - Konstantin Haase
78
短并不意味着简单。我的意思是,这是什么鬼? - Grant Birchmeier
12
将foo转换为布尔类型,检查其是否与foo相同。 - Konstantin Haase
13
请注意,一些检查器(如RuboCop)认为双重否定是不好的风格。 - sschuberth
显示剩余12条评论

94

在Ruby中没有Boolean类,唯一的检查方法就是像你所做的那样(将对象与truefalse进行比较或将对象的类与TrueClassFalseClass进行比较)。但我想不出为什么你需要这个功能,你能解释一下吗?:)

然而,如果你真的需要这个功能,可以通过一些技巧来实现:

module Boolean; end
class TrueClass; include Boolean; end
class FalseClass; include Boolean; end

true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true

2
尝试根据当前值进行类型转换。 - Lance
89
“你为什么要那样做?”(及其变体)是工程师之间最让人烦恼的问题之一 :) - deprecated
13
+1 是因为我可以在 rspec 中这样使用:expect(some_method?(data)).to be_a(Boolean) - Automatico
3
需要检查类型的另一种情况是当您实现数据库适配器并需要用引号 "将字符串" 包裹起来时,但不需要对数字和布尔值进行包裹。 - Daniel Garmoshka
我认为,能够检查变量类型是编程语言中非常基本和有价值的事情,当验证用户输入时尤其重要。没有这些奇怪的技巧支持这一点,这让我感到困惑。经过一些研究,似乎Ruby实现动态类型的方式意味着没有办法推导出类型。Javascript没有这个问题,所以我猜这背后可能有更大的故事。 - Seth

29

如上所述,Ruby中没有布尔类,只有TrueClass和FalseClass,但是你可以使用任何对象作为if/unless的主语,并且除了FalseClass和nil实例之外,一切都为真。

布尔测试返回FalseClass或TrueClass的实例。

(1 > 0).class #TrueClass
以下的 monkeypatch 到 Object 会告诉你某个东西是否是 TrueClass 或 FalseClass 的实例。
class Object
  def boolean?
    self.is_a?(TrueClass) || self.is_a?(FalseClass) 
  end
end

使用irb运行一些测试,得到以下结果

?> "String".boolean?
=> false
>> 1.boolean?
=> false
>> Time.now.boolean?
=> false
>> nil.boolean?
=> false
>> true.boolean?
=> true
>> false.boolean?
=> true
>> (1 ==1).boolean?
=> true
>> (1 ==2).boolean?
=> true

5
更简单的写法是 self == true 或者 self == false。这些是 TrueClass 和 FalseClass 的唯一实例。 - Chuck
@chuck 返回相同的结果,除了 Time.now.boolean? 返回 nil。有什么想法为什么会这样? - Steve Weet
在方法中定义self的类检查有点不符合面向对象编程。你应该定义两个版本的boolean,一个用于TrueClass/FalseClass,另一个用于Object。 - Konstantin Haase
4
原因在于 Ruby 1.8 版本中 Time#== 方法中的一个 bug,导致与非 Time 类型的值进行比较时返回的不是 false 而是 nil。 - Chuck

22
如果你的代码可以合理地编写为case语句,那么这是相当不错的:

如果您的代码可以合理地编写成case语句,那么这是相当不错的:

case mybool
when TrueClass, FalseClass
  puts "It's a bool!"
else
  puts "It's something else!"
end

7
一个布尔类型的对象将具有TrueClass或FalseClass类,因此以下一行代码应该可以解决问题。
mybool = true
mybool.class == TrueClass || mybool.class == FalseClass
=> true

以下内容也将为您提供真/假的布尔类型检查结果。
mybool = true    
[TrueClass, FalseClass].include?(mybool.class)
=> true

4

尝试一下这个表达式 (x == true) ^ (x == false),请注意需要括号,但是这种写法更加简洁美观。

甚至可以通过类似 "cuak" 但不是 "cuak" 的测试,class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)

注意:这个方法非常基础,你甚至可以在其他不提供“布尔值检查”的语言中使用。

注意2:你也可以使用这个方法来判断一个变量是否为以下几个值之一:"red", "green", "blue",只需添加更多的异或操作符即可... 或者说这个变量是否为以下几个值之一:4, 5, 8, 35


Why XOR? Why not OR? - Nakilon

3
这个宝石为Ruby添加了一个布尔类,并提供了实用的方法。 https://github.com/RISCfuture/boolean 使用方法:
require 'boolean'

然后你的
true.is_a?(Boolean)
false.is_a?(Boolean)

将按您的期望完全工作。


-1

不是像你的代码那样。没有叫做Boolean的类。现在有了所有的答案,你应该能够创建一个并使用它。你知道如何创建类吗?我来这里只是因为我自己也在思考这个想法。许多人可能会说“为什么?你只需要知道Ruby如何使用布尔值”。这就是你得到这些答案的原因。所以感谢你的问题。这是一个值得思考的问题。为什么Ruby没有一个Boolean类呢?

NameError: uninitialized constant Boolean

请记住,对象没有类型。它们是类。对象有数据。所以当你说数据类型时,这有点不准确。

另外尝试rand 2,因为rand 1似乎总是给出0。 rand 2将给出1或0 在这里点击运行几次。 https://repl.it/IOPx/7

虽然我不知道如何制作一个布尔类。我已经尝试过了,但是...

class Boolean < TrueClass
  self
end

true.is_a?(Boolean) # => false
false.is_a?(Boolean) # => false

至少我们现在有那个类,但谁知道如何获取正确的值呢?

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