Ruby 关于 succ 方法的一个疑问

shangrenzhidao · 2014年09月28日 · 最后由 shangrenzhidao 回复于 2014年09月29日 · 2506 次阅读
class PowerOfTwo 
  attr_reader :value def initialize(value)
    @value = value
end
def <=>(other)
    @value <=> other.value
end
def succ
    PowerOfTwo.new(@value + @value)
end
def to_s
@value.to_s
end end
p1 = PowerOfTwo.new(4)
p2 = PowerOfTwo.new(32)
puts (p1..p2).to_a
produces:
4 8 16 32

这是搞头上的一个例子: 这里很显然,succ 是定义一个规则,下一个数字是前个数字 的二倍,但自始至终我也没用看到谁去调用这个方法? 而且我在 irb 上做了这样的测试 PowerOfTwo.class.superclass => Module 难道说只要重写了 <=> 就属于 Module 的子类吗?如果是这样的话,succ 一个是 Module 或者其超类的方法,但是我向上并没有发现这个方法,谁可以帮帮我解开这个疑问。

succ 就是 next, 在你定义 range 的时候 (p1..p2) 被呼叫, 决定下一个的值。 默认值是 +1, 在你这里被覆盖为加自身。

Range module 有类似的例子。 http://ruby-doc.org/core-2.1.1/Range.html

楼主可以看下 执行

puts  (p1..p2).to_a 

的时候, 调用了哪些方法

trace = TracePoint.new(:call) {|tp| p tp.method_id }
trace.enable { (p1..p2).to_a }

=begin
 :<=>
:<=>
:succ
:initialize
:<=>
:succ
:initialize
:<=>
:succ
:initialize
:<=>
=end

#2 楼 @googya 还能这么玩呀!长见识了

#1 楼 @billy 也就是 (p1..p2) 就已经说明了这个属于 Range,解析时,ruby 会自动去找 succ 这个方法,ruby 会通过某种运算来赋予类 Range 的性质,而不是像 java 那样必须去实现接口或者继承类,我这么理解对吗?链接的例子 include Comparable,搞头书上没有,这个是怎么回事?

@shangrenzhidao 我不太懂 Java, 不好做比较。 是这样的, 当你定义一个 range 时, Ruby 需要知道 range 的起始, 需要知道间隔。 起始你已经定义了, 是 p1 和 p2。 那么间隔呢, Ruby 会对起点到终点间的每一个元素呼叫 succ(或者 alias next) 来决定。 如果是普通的 range 比如 (1..5), 每一个元素都是 Fixnum, 而 Fixnum 的 succ 会返回其本身 +1, 那么你就会得到 [1,2,3,4,5]。 但这里 p1.succ 被重写了, 会得到本身的翻倍, 下一个元素也是一样, 所以你得到 [4, 8, 16, 32]

#5 楼 @billy 谢谢,不过哪里体现的我定义了 Range

@shangrenzhidao p1..p2就是定义一个 range

#7 楼 @billy 原来如此,呵呵,总拿着别的语言的思维看 ruby、谢谢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册