由于Ruby进行类型转换,如何正确获取索引?
我希望这返回1
[1,2.0,2,3].index(2.0)
#=> 1
我希望这返回2
[1,2.0,2,3].index(2)
#=> 1
答案 0 :(得分:5)
将块与eql?
一起使用是一种方式:
[1,2.0,2,3].index {|e| e.eql? 2.0}
#=> 1
[1,2.0,2,3].index {|e| e.eql? 2}
#=> 2
与==
不同,eql?
仅在接收者和参数具有相同类型和相等值时才返回true
。因此2 == 2.0
会返回true
而2.eql? 2.0
会返回false
。
答案 1 :(得分:1)
您没有得到预期的结果,因为Array#index使用更通用的BasicObject#==代替Object#eql?来比较值,而不使用类型< / em>的参数/值被考虑在内。在鸭子打字语言中,这通常是你想要的。
请考虑以下示例,该示例使用==
将Float与Fixnum进行比较:
2 == 2.0
#=> true
请注意,Ruby认为两个数值相等,尽管它们的类型不同。这是documented behavior。由于Array#index的非块形式将参数为==
的 first 索引返回到索引值,[1,2.0,2,3].index(2.0)
和[1,2.0,2,3].index(2)
都将返回相同的指数。
所有Ruby方法都接受一个可选块,当Kernel#block_given?为真时,某些核心类的行为会有所不同。 Array #index的文档说:
如果给出了一个块...返回该块返回true的第一个对象的索引。如果找不到匹配则返回nil。
区分两种不同类型值的规范方法是使用Array#index的块形式来检查与#eql的对象是否相等?而不是#==。例如:
array = [1,2.0,2,3]
array.index { |i| i.eql? 2 }
array.index { |i| i.eql? 2.0 }
这将返回您期望的值,但需要额外打字。这确实是您问题的首选解决方案。
请考虑以下事项:
class Array
alias_method :old_index, :index
def index value
old_index { |i| i.eql? value }
end
end
[1,2.0,2,3].index 2.0
#=> 1
[1,2.0,2,3].index 2
#=> 2
这可以按照您的预期方式工作,并且您仍然可以在需要原始类型无关的相等性检查时随时使用Array#old_index。但是,请谨慎使用,因为一旦您更改了Array类的正常行为,其他模块或gem可能就不会按预期运行。
很高兴知道你可以这样做,但是用链锯来玩杂耍本身就是一种冒险的活动。您的里程可能会有所不同。