Ruby 用 class_eval 定义方法问题

p_next · 2013年07月05日 · 最后由 iBachue 回复于 2013年07月09日 · 3326 次阅读
class Module
  private
  # Generate a string of code to define attr reader methods.
  def readonly(*syms)
    return if syms.size == 0
    code = ""

    syms.each do |s|
      code << "def #{s}; @#{s}; end\n"
    end

    # Create instance methods.
    class_eval code
  end

这是《The Ruby Programming Language》上的 demo,我的问题是,class_eval 生成的方法如何调用,比如写了 readonly :x 应该是会生成一个

def x
  @x
end

的方法 但是每次都报 undefined method ‘x' for #<Module:0x1fafd30> (NoMethodError) 错误

这段代码到底怎么用呢?

你是怎么 call readonly 的?

同一楼问。。

我这么调用的:

class Module
  private
  # Generate a string of code to define attr reader methods.
  def readonly(*syms)
    return if syms.size == 0
    code = ""

    syms.each do |s|
      code << "def #{s}; @#{s}; end\n"
    end

    # Create instance methods.
    class_eval code
  end
end

A = Module.new

class C
  include A
  readonly :x

def x=(val)
   @x = val
end 
end

c = C.new

puts c.x='hello_ruby'
puts c.x

在 2 楼基础上改,既然是在 Module 上定义,应该是想通用吧?

class Module

  private
  # Generate a string of code to define attr reader methods.
  def readonly(*syms)
    return if syms.size == 0
    code = ""

    syms.each do |s|
      code << "def #{s}; @#{s}; end\n"
    end

    # Create instance methods.
    class_eval code
  end
end

class Test
  readonly :x

  def x=(value)
    @x = value
  end

end

test = Test.new
test.x = 'ok'
puts test.x

#1 楼 @blacktulip 问题解决了,谢谢! 还有一些事不明白,说起来可能有点复杂。

问题 1、模块 A 是类 Module 的一个对象。类 C 中 include 模块 A,于是类 C 继承了模块 A。 为什么可以在类 C 中调用类 Module 的 readonly 私有方法?

问题 2、书上有一段代码

class Point 
  include Comparable
end

include 是类 Module 的一个私有实例方法,它 隐式被 self 调用——这里就是包含模块的类 。...include 是私有方法,它必须 以函数形式 被调用,而不能写成 self.include Comparable 这里的隐式调用和以函数形式调用的机理能不能说明一下,书上没有找到。

太感谢了!!!

#2 楼 @googya 谢谢帮助! 我学艺不精,才知道这里的 class Module 原来就是模块的类。 如果有空帮我看看 4 楼的问题,谢啦!!

#3 楼 @ihlayy 嗯,谢谢!问题解决了

#4 楼 @p_next 我也是近期才学习 ruby,假如说的不对请指正 理解了 ruby 中私有方法的定义,以及方法查找的顺序就可以回答这两个问题 简而言之,私有方法只能以函数形式 (不写 receiver) 被调用(记得=方法是一个特例),而所谓的函数形式并不是指没有 receiver,而是隐式的被 self 调用(即 self 为 receiver,但不能把它写出来) 回到代码上

class Test
  readonly :x  # 函数形式调用(满足调用private method的条件),self为class Test本身

  def x=(value)
    @x = value
  end

end

然后来方法查找,在不考虑特异类的情况下 Test---class--->Class---superclass---->Module 于是定义于 class Module 中 private method 就这样被调用了

问题 1、模块 A 是类 Module 的一个对象。类 C 中 include 模块 A,于是类 C 继承了模块 A。 为什么可以在类 C 中调用类 Module 的 readonly 私有方法?

Ruby 的私有方法和一般语言不相同。大部分语言规定,即使是子类都不能调用父类的私有方法,但 Ruby 则规定,只要以没有上下文的方法名调用的方式就能调用到私有方法,所以子类是可以调用到父类方法的。Test 是一个类,类是 Module 的子类,相当于 Test 其实是 Module 的子类的实例,你在代码里调用readonly :x相当于调用了父类实例方法,并且前面没有指定上下文,符合私有方法的调用规定,因此可以调用。

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