我有两节课Foo
and 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
会议确认:
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
这是一个实例Bar
它继承自Foo
. Bar
'超类'initialize
被调用并且“副作用”发生。到目前为止,这完全是预料之中的。
- I call
some_method
on bar
谁没有它,所以红宝石向上并向右并在里面找到它Foo
- 红宝石跳进里面
some_method
并找到一个向其发送消息的方法self
called basename
- 鲁比回到
Foo
's' initialize
方法?...
第四步完全出乎我的意料。为什么要发送消息到self
导致初始化方法再次被调用?这有记录在任何地方吗?这是预期的吗?
这个可以控制吗?或者有条件地检查我是否在初始化方法内,因为我实际上是在实例化一个类,而不仅仅是随机登陆那里?例如:
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
为什么向 self 发送消息会导致初始化方法再次被调用?这有记录在任何地方吗?这是预期的吗?
这就是如何basename
是实现,它返回一个新实例:
/*
* 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
.
您可以轻松验证这一点:
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>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)