跟进问题How to create a random time between a range 。
Kernel#rand
适用于Time
范围:
require 'time'
rand(Time.parse('9 am')..Time.parse('11:30 am'))
但是当我尝试使用自定义类时,我最终得到了错误:
`rand':没有将Range隐式转换为Integer(TypeError)
class Int
include Comparable
attr_reader :num
def initialize(num)
@num = num
end
def succ
Int.new(num + 1)
end
def <=>(other)
num <=> other.num
end
def to_s
"Int(#{num})"
end
def to_int
@num
end
alias_method :inspect, :to_s
end
puts rand(Int.new(1)..Int.new(3))
为什么呢?我在自定义课程中缺少什么?我们可以在rand(Range)
中使用这样的自定义类吗?
答案 0 :(得分:4)
我不知道Kernel#rand
对Range
论点所期望的任何文档,但我们可以通过覆盖{{1}来了解正在发生的事情。在你的班级,然后看着事情崩溃:
respond_to?
这样做告诉我们def respond_to?(m)
puts "They want us to support #{m}"
super
end
想要调用rand
个实例上的#-
和#+
方法。鉴于Int
设计用于处理整数,这确实有意义。
因此,我们引入了加法和减法的快速实现:
rand(a..b)
我们开始通过调用def -(other)
self.class.new(to_int - other.to_int)
end
def +(other)
self.class.new(to_int + other.to_int)
end
来获取rand Int
。
我不确定在哪里(或者如果)记录下来,所以你不得不原谅一点挥手。我通常会花一些时间来处理Ruby源代码来回答这类问题但我现在没时间。
答案 1 :(得分:3)
为了给@ mu-too-short-short的答案添加更多内容,我检查了Random#rand
的来源,以下是rand(Range)
的当前实现逻辑:
从vmax
对象(call range_values
)获取开始,结束和Range
,其中vmax
计算为(call id_minus
) :
vmax = end - begin
vmax
将用作稍后生成随机数的上限。
这需要自定义类定义-
方法。
根据vmax
:
如果它不是Float
且可以强制转换为Integer
(rb_check_to_int
),则生成小于Integer
的随机vmax
。< / p>
在这种情况下,-
方法应返回Integer
或响应to_int
方法的对象。
如果是Numeric
且可以使用Float
转换为to_f
,(rb_check_to_float
),则生成小于Float
的随机数vmax
-
。
在这种情况下,Numeric
方法应该返回Float
个号码,可以使用方法to_f
转换为begin
。
将随机数添加到+
以产生结果(call id_add
)。
这要求自定义类定义Integer
方法,该方法接受步骤2中生成的随机数的结果(Float
或rand
)并返回owl:sameAs
的最终结果。
答案 2 :(得分:0)
我相信这个错误是因为您尝试在自定义类的对象上使用rand()。
`rand': no implicit conversion of Range into Integer (TypeError)
此错误消息明确提到ruby无法将您的范围转换为整数。根据您的代码段,以下工作,可能是您正在寻找的。 p>
puts rand(Int.new(1).to_int..Int.new(3).to_int)