`method_missing': stack level too deep (SystemStackError)

今天遇到一个很有意思的一段关于method_missing的代码:

 

 

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize
    3.times do
      number = rand(10) + 1
      puts "#{number}..."
    end
   "#{person} got a #{number}"
  end
end

r = Roulette.new
puts r.bob

 

关于method_missing,就是在ancestors chain中没有找到改方法时,ruby就会去执行method_missing方法

这段代码的意思是,重写method_missing方法,当执行r.bob时,因为没有定义bob方法,程序会走到method_missing

方法中,将人名转换成大写,然后循环3次,得到一个随机数,那么期望的结果应该是:

 

4....

2....

7....

BOB got a 7

 

但是执行结果却是个死循环,最后程序会抛出异常:`method_missing': stack level too deep (SystemStackError)

 

问题的原因就在这个最后一句中得number变量:"#{person} got a #{number}"

这里的number变量是定义在blok中得,在blok外,number已经超出了作用范围,ruby不知道它是一个变量,会把它当成是一个不带括号的方法进行调用,此时就会重新调用method_missing方法,如此反复,就成了死循环了

 

所以在block外定义number = 0,程序即可正确执行

 

 

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize
    number = 0
    3.times do
      number = rand(10) + 1
      puts "#{number}..."
    end
   "#{person} got a #{number}"
  end
end

r = Roulette.new
puts r.bob

 

另外,为了避免这样的麻烦,当执行某个方法时,你不知道如何处理,记得要退回到Kernel的method_missing方法。

 

 

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize
    super unless %w[Bob Frank Bill].include?(person)
    number = 0
    3.times do
      number = rand(10) + 1
      puts "#{number}..."
    end
   "#{person} got a #{number}"
  end
end

r = Roulette.new
puts r.bob

你可能感兴趣的:(method_missing)