TypeOfClass === TypeOfClass
false
field.class
这个事实让我感到反直觉。在以下代码中,即使false
是同一个类,它的计算结果为case field.class
when Fixnum, Float
field + other_field
when Date, DateTime, Time
field
else
puts 'WAT?'
end
:
Fixnum === Fixnum # => false
Class === Class # => true
我这样做了:
Integer === 3 # => true
Fixnum === 3 # => true
3.class # => Fixnum
我找到another thread:
Numeric === Integer
我找不到这种语言设计的原因。语言设计师在这种行为中的想法是什么?
我认为这与another thread中提供的答案相关。假设Integer
Numeric
是更具体的Numeric === Integer #=> false
类型,这并不是不自然的。但是,它不是:
case
我认为===
语句或Numeric
需要谨慎。如果此运算符属于we think it is ,则Numeric
应为Integer
,Numeric
应为true
等。
有没有人解释为什么此功能不会扩展到类?如果比较的类是类'祖先'的成员,似乎很容易返回Time
。
根据下面提交的答案,该代码最初是对Timeframe = Struct.new(:from, :to) do
def end_date
case self.to
when Fixnum, Float
self.from + self.to
when Date, DateTime, Time
self.to
else
raise('InvalidType')
end
end
end
进行分类(由ActiveSupport:CoreExtensions::Integer::Time
和ActiveSupport:CoreExtensions::Float::Time
进行了扩展):
tf = Timeframe.new(Time.now, 5.months)
# => #<struct Timeframe from=Tue Dec 10 11:34:34 -0500 2013, to=5 months>
tf.end_date
# => RuntimeError: InvalidType
# from timeframe.rb:89:in `end_date'
在控制台中,我得到:
{{1}}
答案 0 :(得分:5)
我真的没有看到这里的问题。对于类,大小写相等运算符会询问左手参数是否是类(或任何子类)的实例。所以Fixnum === Fixnum
真的问:“Fixnum类本身是Fixnum的子类吗?”不,不是。
班级Class
本身是一个班级吗? Class === Class
,是的。
操作员的观点是你不需要去找班级。在开头没有.class
方法的情况下使用case语句有什么问题?
case field
when Fixnum, Float
field + other_field
when Date, DateTime, Time
field
else
puts 'WAT?'
end
如果你有一个更复杂的例子,你可以编写自己的lambdas来简化case语句:
field_is_number = -> x {[Fixnum, Float].include? x.class}
field_is_time = -> x {[Date, DateTime, Time].include? x.class}
case field.class
when field_is_number
field + other_field
when field_is_time
field
else
puts 'WAT?'
end
答案 1 :(得分:1)
如果其中一个操作数是一个类,则检查第二个操作数是否为此类实例。如果它们都是类,则它将返回false,除非它们中至少有一个是Class。
请注意,Class既是一个类又是一个自身的实例 - 它可能是最大的ruby奇怪的TBH,但它非常有意义。
我投票支持保持这种逻辑的原因是我们可以编写那些不错的case语句而不向对象添加.class
。
要点:
ClassName === object <=> object.kind_of? ClassName
但是,如果你真的想要覆盖这个用途:
class Class
def ===(object)
return object == self if object.is_a? Class
super
end
end
答案 2 :(得分:1)
那是Module#===
及其预期行为:
mod === obj→true或false
案例平等 - 如果 anObject 是 mod 的实例或其中一个,则返回
true
mod 的后代。模块的用途有限,但可以在case
中使用 用于按类对对象进行分类的语句。
它只返回obj.kind_of? mod
:
Fixnum === Fixnum #=> false
Fixnum.kind_of? Fixnum #=> false
Class === Class #=> true
Class.kind_of? Class #=> true
String === "foo" #=> true
"foo".kind_of? String #=> true
由于其类层次结构, 3
是Integer
和Fixnum
:
3.kind_of? Integer #=> true
3.kind_of? Fixnum #=> true
3.class.ancestors #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Numeric
不是Integer
,而是Class
:
Numeric.kind_of? Integer #=> false
Numeric.kind_of? Class #=> true
但3
,(2/3)
和1.23
都是Numeric
:
3.kind_of? Numeric #=> true
Rational(2, 3).kind_of? Numeric #=> true
1.23.kind_of? Numeric #=> true
底线:对于case
语句,只需使用case obj
代替case obj.class
。
<强>更新强>
您收到此错误是因为5.months
未返回Integer
,而是ActiveSupport::Duration
:
Integer === 5.months #=> false
ActiveSupport::Duration === 5.months #=> true
使用5.months.to_i
调用您的方法或将ActiveSupport::Duration
添加到您的类中应修复它。