ruby 在overriden initialize [duplicate]中使用super

kulphzqa  于 2023-05-28  发布在  Ruby
关注(0)|答案(3)|浏览(105)

此问题已在此处有答案

When monkey patching an instance method, can you call the overridden method from the new implementation?(3个答案)
4天前关闭。
为什么我没有得到'init'字符串?

class Dwa
  attr_reader :nazwa

  def initialize()
    puts 'init'
    @nazwa = "dwa"
  end
end

class Dwa #open this same object definition
  def initialize()
    super #or super()
    @nazwa = "trzy"
  end
end

d = Dwa.new
puts "#{d.nazwa}"

我再次打开对象并重新定义initialize
当我用未修改的类运行代码时,我打印initdwa
如何修改initialize并仍然运行puts 'init'
我期望:

$ run.rb
init
trzy
mspsb9vt

mspsb9vt1#

主要问题是重新开放Dwa并重新定义initialize取代旧的initialize。由于super只适用于引用超类,因此在这种情况下它是无用的。
要调用旧的行为,您必须将旧的initialize方法存储在某个地方,并从新定义中调用它。一种方法是使用instance_method获取UnboundMethod并将其存储在变量中。然后从initialize的重新定义调用它(使用bind_call)。

# re-opening Dwa class
class Dwa
  old_initialize = instance_method(:initialize)

  define_method :initialize do
    old_initialize.bind_call(self)
    @nazwa = "trzy"
  end
end

我们在这里使用define_method :initialize而不是def initialize的原因是上下文切换。将define_method :initialize与一个块一起使用允许我们访问外部的old_initialize变量,这在def initialize中是不可能的。
或者,您可以更改类结构/层次结构,并使用Dwa作为其超类定义一个新类。

class NewDwa < Dwa
  def initialize
    super
    @nazwa = "trzy"
  end
end
aiqt4smr

aiqt4smr2#

为什么我没有得到'init'字符串?
Doe的超类是ObjectObject#initialize不打印任何东西,因此您不会得到任何打印输出。
modyfy如何初始化并仍然运行将'init'

def initialize
  print 'init'
  @nazwa = "trzy"
end
hmae6n7t

hmae6n7t3#

如果您决定重写此方法,为什么不完全显式地重写它呢?
也许这是最好的选择
但如果你还想一些黑客,你可以使用别名

# original class
class Dwa
  attr_reader :nazwa

  def initialize
   puts 'init'
   @nazwa = "dwa"
  end
end
# overriden class
class Dwa
  alias_method :original_initialize, :initialize

  def initialize
   original_initialize
   @nazwa = "trzy"
  end
end
d = Dwa.new
# will print init

puts d.nazwa
# will print trzy

相关问题