通用代码:
class ThingA end
class ThingB end
class ThingC end
为了设置上述类型的条件检查,我使用了基本的“if!...”结构,它可以产生预期的准确结果。
示例代码if! ...
obj = ThingA.new
puts 'yes it is a ThingC' if !obj.is_a?(ThingA) && !obj.is_a?(ThingB) # works ok
# stdout => nothing
obj = ThingB.new
puts 'yes it is a ThingC' if !obj.is_a?(ThingA) && !obj.is_a?(ThingB) # works ok
# stdout => nothing
obj = ThingC.new
puts 'yes it is a ThingC' if !obj.is_a?(ThingA) && !obj.is_a?(ThingB) # works ok
# stdout => yes it is a ThingC
考虑到“除非”是基本“if!...”构造的更具描述性的替代,我使用“除非”来实现上述。
示例代码,除非:
obj = ThingA.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) && obj.is_a?(ThingB) # BUG
# stdout => yes it is a ThingC
obj = ThingB.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) && obj.is_a?(ThingB) # BUG
# stdout => yes it is a ThingC
obj = ThingC.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) && obj.is_a?(ThingB) # ???
# stdout => yes it is a ThingC
显然,“除非”版本无法产生相同的准确结果。
基于这些简单而直截了当的结果,任何人都难以得出结论“除非准确地处理多个条件”吗?
答案 0 :(得分:7)
布尔逻辑变得难以用unless
进行解析。您可以使用if
重写它:
unless a || b
相当于if !(a || b)
,相当于if !a && !b
unless a && b
相当于if !(a && b)
,相当于if !a || !b
obj.is_a?(ThingA) && obj.is_a?(ThingB)
和false
是独立的类,则 ThingA
必须为ThingB
。
如果一个类是另一个类的子类,那么它只能是true
。在这种情况下,您只需要检查obj
是否为子类实例:
obj.is_a?(ThingA) && obj.is_a?(Object)
是obj
对象时, ThingA
才为真,所以你可以写一下:
obj.is_a?(ThingA)
对于您的示例,您应该使用case
:
obj = ThingA.new
case obj
when ThingA
puts "yes, it is a ThingA"
when ThingB
puts "yes, it is a ThingB"
when ThingC
puts "yes, it is a ThingC"
else
puts "no, it is some other Object"
end
或
case obj
when ThingA, ThingB, ThingC
puts "yes, it is a Thing A B or C"
else
puts "no, it is some other Object"
end
或
puts "yes, it is a #{obj.class}"
他们回来了:
yes, it is a ThingA
yes, it is a Thing A B or C
yes, it is a ThingA
答案 1 :(得分:2)
这里的问题是逻辑和或或,当你否定一个逻辑函数时,等效的是opossite和操作符的优先级:修饰符之前的逻辑函数
德摩根的法律提供了一种分配否定的方式 分离和结合:
¬ ( a ∨ b ) ≡ ( ¬ a ∧ ¬ b ),
和 ¬(a∧b)≡(¬a∨¬b)
在你的情况下,
(不是(a)而不是(b))然后你否定它=>不是(a或b)
并且除非=>不是
irb(main):001:0> class ThingA end
class ThingB end
class ThingC end
=> nil
irb(main):002:0> => nil
irb(main):003:0> => nil
irb(main):004:0> obj = ThingA.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) || obj.is_a?(ThingB
obj = ThingB.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) || obj.is_a?(ThingB)
obj = ThingC.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) || obj.is_a?(ThingB)
<ThingA:0x000000025fc060>
irb(main):005:0> => nil
<ThingB:0x00000002749d00>
irb(main):009:0> => nil
<ThingC:0x000000027be420>
irb(main):013:0> yes it is a ThingC
=> nil
答案 2 :(得分:0)
我在这里看不到任何错误。你得到的输出是合乎逻辑的。让我分解您的代码。
obj = ThingA.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) && obj.is_a?(ThingB) # BUG
obj.is_a?(ThingB)
是false
。所以false && obj.is_a?(ThingB)
是false
。 unless false
是true
。所以它打印出来。
obj = ThingB.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) && obj.is_a?(ThingB)
obj.is_a?(ThingA)
是假的。 false && obj.is_a?(ThingB)
是false
。 unless false
是true
。所以它打印出来。
obj = ThingC.new
puts 'yes it is a ThingC' unless obj.is_a?(ThingA) && obj.is_a?(ThingB)
obj.is_a?(ThingA)
是false
。 false && obj.is_a?(ThingB)
为false
。unless false
为true
。所以它打印出来。
答案 3 :(得分:0)
注意:由于我想发布的文字不适合作为评论,我不得不将其作为答案分享。
谢谢大家的所有宝贵答案和评论。现在,正如我已经提到过的那样,我想建立一个&#34;无论是x AND Nor y&#34;过滤。我去了if !obj.is_a?(ThingA) && !obj.is_a?(ThingB)
。它不仅有效,而且还清楚地表达了意图&#34; ThingA和Nor ThingB&#34;。
现在问题出现了,为什么我从此语句中删除了所有!
,将if
替换为unless
,并期望新版本产生相同的结果?答案在于我们中的一些/大多数人首先被介绍到unless
。类似于&#34; Ruby的语句也可以执行,除非测试与if测试完全相反......&#34;并且&#34;想想除非作为表达“如果不是”的替代方式。&#34; (来自Huw Collingbourne的The Book of Ruby的直接引用:pg87),基本上导致(更像是误导)我相信unless
可以在任何场景中用作if !
的替代。这就是我期望它在这里工作的原因。
新年的决议第1项:unless
严格禁止任何涉及多个条件的内容。
任何仍然坚持用if !
解决复合条件unless
问题的人都可以通过将整个论点包含在!()
中来实现。例如,上述内容可以解决为unless !( !obj.is_a?(ThingA) && !obj.is_a?(ThingB) )
。仅在学术精神上分享。不要沮丧地投票。