为什么`1i.to_i`引发`RangeError`而不是`NoMethodError`?

时间:2019-02-21 14:14:52

标签: ruby

NoMethoErrorto_i引发,仅仅是因为该类没有方法:

[].to_i # >> NoMethodError (undefined method `to_i' for []:Array)

当然,1i拥有方法to_ito_f,因此它可以对它们做出响应。但实际上,这看起来很棘手。

1i.respond_to?(:to_i) # => true
1i.to_i # >> RangeError (can't convert 0+1i into Integer)

Range类从何而来?

3 个答案:

答案 0 :(得分:9)

  

当然,1i拥有方法.to_i和.to_f,因此它可以对它们进行响应。但是实际上,这看起来非常棘手!

是的,它会回应他们。当您在复杂文字to_i上调用1i时,该方法将抛出RangeError。这与Range类无关;它告诉您,尽管1i具有类to_i的{​​{1}}方法,但是它的特定值并不是可以获取有意义结果的值。

或者换句话说,Complex::to_i 在虚部不为零甚至不精确的对象上调用时就是这样做的:

  

to_i→整数

     

如果可能,将值返回为整数(虚数部分应   完全为零)。

Complex

Complex(1, 0).to_i #=> 1 Complex(1, 0.0).to_i # RangeError Complex(1, 2).to_i # RangeError 粗略地传达了一个论点在提供该论点的函数范围之外,即在数学意义上为“范围”。 RangeError与目标方法相比,在将“范围”意义应用于目标对象时有点不寻常,但这仍然是有道理的。

答案 1 :(得分:2)

文档所说的是

Returns the value as an integer if possible (the imaginary part should be exactly zero).

因此,它看起来并不太有用,它仅在i为零时有效。

答案 2 :(得分:2)

Complex#to_i的规范如Ursus和John Bolinger在回答中所说。

定义Complex#to_i的原因(因此不会引发NoMethoError错误)是因为当虚部不为零时它返回计算值,因此需要对其进行定义。您不能仅针对某个类的实例引发NoMethodError

之所以没有引发更熟悉的异常(例如ArgumentError),是因为它不是参数,而是接收者。

要针对某个类的某些实例引发错误,最合适的方法是RangeError;没有其他Exception类似乎更合适。