rand(Range) - 没有将Range隐式转换为Integer

Ari*_*iao 5 ruby

关于如何在范围之间创建随机时间 的问题的后续跟进.

Kernel#rand适用Time范围:

require 'time'
rand(Time.parse('9 am')..Time.parse('11:30 am'))
Run Code Online (Sandbox Code Playgroud)

但是当我尝试使用自定义类时,我最终得到了错误:

`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))
Run Code Online (Sandbox Code Playgroud)

为什么?我在自定义课程中缺少什么?我们可以使用这样的自定义类rand(Range)吗?

mu *_*ort 4

我不知道任何关于论证具体Kernel#rand期望的文档Range,但我们可以通过在你的类中重写来看看发生了什么respond_to?,然后观察事情的崩溃:

def respond_to?(m)
  puts "They want us to support #{m}"
  super
end
Run Code Online (Sandbox Code Playgroud)

这样做告诉我们rand想要在您的实例上调用#-#+方法Intrand(a..b)鉴于它是为处理整数而设计的,这确实有一定意义。

所以我们引入了加法和减法的快速实现:

def -(other)
  self.class.new(to_int - other.to_int)
end

def +(other)
  self.class.new(to_int + other.to_int)
end
Run Code Online (Sandbox Code Playgroud)

我们开始Int从对 的调用中获取 rand rand


我不确定在哪里(或是否)记录了这一点,所以您必须原谅我挥手。我通常会花一些时间研究 Ruby 源代码来回答此类问题,但我现在没有时间。