在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
?
答案 0 :(得分:5)
在ruby中,任意类可以通过定义coerce
方法选择对其他类型进行强制。详细描述了here。
答案 1 :(得分:2)
Ruby中的类型强制/转换有四种协议,三种通用协议,一种特定于数字的算术运算。
当对象可以有意义地表示为另一个类的实例时,它们会响应单字母类型转换方法,例如to_s
,to_i
,to_f
等。响应其中一个非常低:如果有任何方式,对象可以表示为,例如,一个不完全虚假的整数,那么它可以响应to_i
。例如。将nil
表示为整数0
是有道理的,因此nil
会回复to_i
。同样,将nil
表示为空字符串是有意义的,因此它会响应to_s
。
这更加严格。只有当一个对象可以被合理地解释为与另一个类的实例相同类型时,才允许它回复to_str
,to_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#Integer
,Kernel#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