向“自身"发送消息会导致初始化方法被调用? [英] Sending a message to 'self' causes initialize method to be called?
问题描述
我有两个类Foo
和Bar
:
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
因此将其分解:
- 我实例化
bar
,这是从Foo
继承的Bar
的实例.Bar
的超类'initialize
被调用,并且发生副作用".到目前为止,这是完全可以预期的. - 我打电话给
bar
上的some_method
谁没有它,所以红宝石在右边和右边找到并在Foo
内找到它. - Ruby在
some_method
中跳入并找到一种向self
发送消息的方法,称为basename
- Ruby返回到
Foo
的initialize
方法吗?...
- I instantiate
bar
which is an instance ofBar
which inherits fromFoo
.Bar
's superclass'initialize
is called and the "side effect" happens. So far this is totally expected. - I call
some_method
onbar
who doesn't have it so ruby goes up and to the right and finds it inside ofFoo
- Ruby hops inside of
some_method
and finds a method that's sending a message toself
calledbasename
- 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屋!