什么可以强制转换为Ruby中的整数?

时间:2017-01-28 20:17:54

标签: ruby

在Ruby中,例如,如果您尝试2 + nil,则会得到

  

TypeError:nil无法强制转换为Integer

但是,这让我想知道是否有任何东西可以强制进入Integer。许多次Integer被强制转换为其他数字类型,例如

(2 + Rational('1/2')).class 
# => Rational
(2 + 0.5).class
# => Float
(2 + 1i).class
# => Complex

并且,Ruby中的布尔人不会被强迫Integer。那么,什么被强迫进入Integer

3 个答案:

答案 0 :(得分:5)

在ruby中,任意类可以通过定义coerce方法选择对其他类型进行强制。详细描述了here

答案 1 :(得分:2)

Ruby中的类型强制/转换有四种协议,三种通用协议,一种特定于数字的算术运算。

单字母类型转换

当对象可以有意义地表示为另一个类的实例时,它们会响应单字母类型转换方法,例如to_sto_ito_f等。响应其中一个非常低:如果有任何方式,对象可以表示为,例如,一个不完全虚假的整数,那么它可以响应to_i 。例如。将nil表示为整数0是有道理的,因此nil会回复to_i。同样,将nil表示为空字符串是有意义的,因此它会响应to_s

多字母类型转换

这更加严格。只有当一个对象可以被合理地解释为与另一个类的实例相同类型时,才允许它回复to_strto_int等。例如,Ruby核心库中有10个to_i实现,但to_int只有4个。

在纯粹的OO中,对象是什么类的实例应该无关紧要。如果一个对象的行为类似于一个整数,那么 ,就所有意图和目的而言,都是一个整数,无论​​它是什么类的实例。不幸的是,Ruby并不是纯粹的OO。例如,在YARV上,Array#[]是通过使用机器整数索引到C数组来实现的。 (在JRuby上,它正在索引到Java数组,类似于Opal,MRuby,Rubinius,IronRuby,MagLev,......)这意味着只有实际 Integer实例的对象class可以用于数组索引,因为Ruby实现只知道如何从Integer中提取机器整数(Java integer,...),而不是从行为像整数的任意对象中提取;它知道Integer的内部存储器结构是什么样的,但它不知道MyInteger的内部存储器结构是什么样的。

但是,作为逃生舱,Array#[]将尝试首先使用to_int将对象转换为整数。所以,它并不完全是OO,但至少可以通过将自己转换为整数来选择参与数组索引。

同样,&一元&符前缀“convert-to-block”运算符理论上仅适用于Proc,但它会先调用to_proc ,让对象有机会将自己转换为Proc

大写字母类型转换

Kernel中定义了几个工厂方法,其名称与核心类匹配,例如Kernel#IntegerKernel#Float等。这些目的是将各种对象转换为各自的类。它们在某种意义上更宽松,因为它们接受比多字母类型转换更广泛的对象。但从某种意义上说,它们也更加严格,因为它们被允许提出异常。 to_方法不允许引发异常:它们存在,然后它们必须工作,或者它们根本不存在。

例如,

Kernel#Integer接受一个字符串,并尝试将其解析为整数。

算术运算强制

该协议特定于数字和算术运算。当你为一个算术运算发送一个数字的消息,并传递一个该数字不知道如何处理的参数时,它会将coerce这个数字对的参数请求更通用的一对类型

所以,假设您有a + b,而a不知道如何处理b,那么a + b.coerce(self)方法,它会调用b[a_converted_to_a_more_general_type, b_converted_to_a_more_general_type]会回复a,之后a_converted_to_a_more_general_type + b_converted_to_a_more_general_type将重试调用class Roman < Numeric def initialize(str) # dummy implementation for the sake of this example @num = 5 if str == 'V' end def coerce(other) puts "`coerce` called with #{other.inspect}, which is a #{other.class}" [other, @num] end def to_int puts '`to_int` called' @num end end 2 + Roman.new('V') # `coerce` called with 2, which is a Integer #=> 7 ('a'..'g').to_a[Roman.new('V')] # `to_int` called #=> 'f'

{{1}}

答案 2 :(得分:-1)

如果字符串只包含数字,则可以强制转换为整数:

Integer('1') # => 1
Integer('1.0') # => ArgumentError: invalid value for Integer(): "1.0"

如果你试图确保输入的值真的是一个整数而不是一个浮点数,或者它是否有任何其他“垃圾”,这可能很有用:

Float('1.0') # => 1.0

如果要将值强制转换为整数,并且不尝试验证输入,那么您可能希望使用to_i代替,这样可以更好地获得可用的结果而不会发生异常:

1.to_i  # => 1
'1'.to_i  # => 1
Time.now.to_i # => 1485640961
''.to_i # => 0
nil.to_i  # => 0

1.to_i + nil.to_i # => 1