向“自身"发送消息会导致初始化方法被调用? [英] Sending a message to 'self' causes initialize method to be called?

查看:64
本文介绍了向“自身"发送消息会导致初始化方法被调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个类FooBar:

require 'pry-byebug'
require 'fileutils'

class Foo < Pathname
  include FileUtils
  def initialize(path)
    puts "Inside Foo init..."
    super
    puts "Side effect happening..."
  end

  def some_method
    puts "Inside some_method inside Foo..."
    basename.to_s
  end
end

class Bar < Foo
end

bar = Bar.new('bar')
# binding.pry
bar.some_method

这是输出:

Inside Foo init...
Side effect happening...
Inside some_method inside Foo...
Inside Foo init...
Side effect happening...

如您所见,副作用"发生了两次.查看pry-byebug会话可确认:

As you can see the "side effect" is happening twice. Taking a look at a pry-byebug session confirms:

Inside Foo init...
Side effect happening...

From: /Users/max/Dropbox/work/tmp/super_test/foo.rb @ line 23 :

    18: class Bar < Foo
    19: end
    20:
    21: bar = Bar.new('bar')
    22: binding.pry
 => 23: bar.some_method

[1] pry(main)> step

From: /Users/max/Dropbox/work/tmp/super_test/foo.rb @ line 13 Foo#some_method:

    12: def some_method
 => 13:   puts "Inside some_method inside Foo..."
    14:   basename.to_s
    15: end

[1] pry(#<Bar>)> step
Inside some_method inside Foo...

From: /Users/max/Dropbox/work/tmp/super_test/foo.rb @ line 14 Foo#some_method:

    12: def some_method
    13:   puts "Inside some_method inside Foo..."
 => 14:   basename.to_s
    15: end

[1] pry(#<Bar>)> step

From: /Users/max/Dropbox/work/tmp/super_test/foo.rb @ line 7 Foo#initialize:

     6: def initialize(path)
 =>  7:   puts "Inside Foo init..."
     8:   super
     9:   puts "Side effect happening..."
    10: end

因此将其分解:

  1. 我实例化bar,这是从Foo继承的Bar的实例. Bar的超类'initialize被调用,并且发生副作用".到目前为止,这是完全可以预期的.
  2. 我打电话给bar上的some_method谁没有它,所以红宝石在右边和右边找到并在Foo内找到它.
  3. Ruby在some_method中跳入并找到一种向self发送消息的方法,称为basename
  4. Ruby返回到Fooinitialize方法吗?...
  1. I instantiate bar which is an instance of Bar which inherits from Foo. Bar's superclass' initialize is called and the "side effect" happens. So far this is totally expected.
  2. I call some_method on bar who doesn't have it so ruby goes up and to the right and finds it inside of Foo
  3. Ruby hops inside of some_method and finds a method that's sending a message to self called basename
  4. Ruby goes back to Foo's' initialize method?...

第4步让我完全措手不及.为什么向self发送消息会导致初始化方法再次被调用?这在任何地方都有记录吗?这是预期的吗?

Step 4 is catching me completely by surprise. Why would sending a message to self cause the initialize method to get called again? Is this documented anywhere? Is this expected?

可以控制吗?还是有条件地检查我是否在initialize方法内,因为我实际上是在实例化一个类,而不仅仅是随机地登陆那里?例如:

Is it possible to control this? Or conditionally check if I'm inside the initialize method because I'm actually instantiating a class and not just randomly landing there? For example:

class Foo < SomeClass
  def initialize args
    @args = args
    if instantiating_a_class?
      puts "Side effect happening..."
    else
      puts "Don't do anything..."
    end
  end
end

推荐答案

为什么向自身发送消息会导致初始化方法再次被调用?这在任何地方都有记录吗?这是预期的吗?

Why would sending a message to self cause the initialize method to get called again? Is this documented anywhere? Is this expected?

这就是实现basename的方式,它返回一个新实例:

That's how basename is implement, it returns a new instance:

/*
 * Returns the last component of the path.
 *
 * See File.basename.
 */
static VALUE
path_basename(int argc, VALUE *argv, VALUE self)
{
    VALUE str = get_strpath(self);
    VALUE fext;
    if (rb_scan_args(argc, argv, "01", &fext) == 0)
        str = rb_funcall(rb_cFile, rb_intern("basename"), 1, str);
    else
        str = rb_funcall(rb_cFile, rb_intern("basename"), 2, str, fext);
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}

最后一行等效于调用new.

您可以轻松地进行验证:

You can verify this easily:

class Foo < Pathname
  def initialize(path)
    puts "initialize(#{path.inspect})"
    super
  end
end

foo = Foo.new('foo/bar/baz')
# prints initialize("foo/bar/baz")
#=> #<Foo:foo/bar/baz>

foo.basename
# prints initialize("baz")
#=> #<Foo:baz>

这篇关于向“自身"发送消息会导致初始化方法被调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆