3

我正在阅读《The Well-Grounded Rubyist》这本书,我突然想到了这个问题。我知道在 Ruby 中可以重新打开一个类并覆盖该方法。

例子:

class A
  def x
    "First definition of x"
  end

  def x
    "Second definition of x"
  end
end

test = A.new
test.x #returns "Second definition of x"

基于上面的结果,我很好奇是否可以attr_accessor用我自己的(随机)定义覆盖类方法。这就是我的想法:

class Dummy
  attr_accessor :test

  def self.attr_accessor(method_name)
    puts "Overwrite the default functionality of attr_accessor by printing this text instead."
  end
end

d = Dummy.new
d.test #not sure why this returns nil instead of putting my message
Dummy.attr_accessor(test) #fails because of ArgumentError: wrong number of arguments (0 for 2..3)

对于上面的两个示例,我希望通过修补并提出问题来获得您的洞察力,从而更好地理解 Ruby。

4

4 回答 4

6

您走在正确的道路上,但类定义在运行时按顺序执行。您需要在调用它之前定义您的新方法,否则原始方法将用于该方法。

如果你这样做

class Dummy
  def self.attr_accessor(method)
    puts 'your message here'
  end
  attr_accessor :test # message printed
end

d = Dummy.new
d.test # raises an error, since we aren't creating a test method anymore
Dummy.attr_accessor(test) #will still fail, read on

test是 Ruby 中的一个方法,对应于 shell 中的test内置方法。这种方法就是你最后得到错误的原因。你真正想要的是

Dummy.attr_accessor(:test1)

请注意,您将无法调用 normal attr_accessor,因为它是self类定义内部的类实例上的私有方法。(IOW,attr_accessor是 的私有实例方法Module,在执行类定义时,self是 的实例Module

于 2013-01-28T03:26:34.143 回答
3

是的,这是可能的,而你刚刚做到了!

d.test #not sure why this returns nil instead of putting my message

返回nil是因为您attr_accessor :test在下面重新定义它之前使用了它,因此,Ruby 执行了attr_accessor的默认行为并在Dummy类中创建了一个成员和访问器。它返回nil是因为成员的值未设置nil...。

Dummy.attr_accessor(test) #fails because of ArgumentError: wrong number of arguments (0 for 2..3)

失败不是因为你认为的原因。此调用有效:

Dummy.attr_accessor("method_name") 

问题是您正在调用一个名为的方法test并且没有提供它的所有预期值。请参阅Kernel.test() http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-test的文档。

您看到的错误消息是因为您错误地调用了测试方法,而不是因为重新定义attr_accessor.

于 2013-01-28T03:35:33.983 回答
2

在您的Dummy课程中,调用的Class版本attr_accessor是因为在调用时尚Dummy未定义版本attr_accessor。如果在调用之前移动定义,行为会有所不同。

class Dummy    
  def self.attr_accessor(method_name)
    puts "Overwrite the default functionality of attr_accessor by printing this text instead."
  end

  attr_accessor :test
end

这将在读取类定义时打印您的消息。当您尝试testDummy对象上调用该方法时,您会收到一个错误,因为没有定义这样的方法。

于 2013-01-28T03:26:23.283 回答
1

如果你颠倒你的attr_accessor电话和你的顺序会发生什么def self.attr_accessor?我不知道这是否会解决它,但你当然不能按照你的顺序去做。请记住,当您打开带有类似 行的类时class Dummy,您正在实时执行真实代码。所以首先你打电话attr_accessor然后你试图重新定义它。好吧,我不知道您是否可以这样重新定义它,但是您当然需要在调用它之前尝试重新定义它,否则您将调用旧版本!

于 2013-01-28T03:26:02.523 回答