require和load wrt之间的区别是“加载”和“执行”

时间:2016-12-31 20:10:06

标签: ruby

以下是Kernel文档中的一些代码段:

Kernel#load

  

在文件filename ...

中加载并执行Ruby程序

Kernel#require

  

加载给定名称......

我知道requireload之间存在差异,例如:

  • require会在rb分机上发布,而load则不会
  • require会将ruby文件路径存储在$LOADED_FEATURES又名$"内,而load则不会
  • require会在再次“加载”文件之前搜索$LOADED_FEATURES,而load将不会

我想知道“加载”这个词与“执行”这个词之间的区别。

文档使它看起来像是两个不同的东西。对我来说,“加载”意味着“嘿,我现在知道这个文件”,而“执行”意味着“嘿,我现在知道这个文件了,我也要运行所有命令”

但我认为这不对。

例如,给定以下结构:

$  tree
.
├── bar.rb
├── baz.rb
└── foo.rb

0 directories, 3 files

与foo.rb:

$LOAD_PATH << __dir__
require 'bar'
load 'baz.rb'

bar.rb:

puts "Inside of bar..."

baz.rb:

puts "Inside of baz..."

当我运行foo.rb时,我希望“在baz ...内部”打印而不是“在栏内......”因为load“加载并执行”而{{1}只是“加载”。但实际发生的事情似乎都是“执行”:

require

“加载”和“执行”ruby文件之间有区别吗?

1 个答案:

答案 0 :(得分:7)

始终执行文件。

在Ruby中没有加载文件而不执行文件。一切都是Ruby中的声明,必须执行。即使classdef也只是陈述。

这里说明这是一个愚蠢的例子

class Mystery < [Array, Object, String, Fixnum].sample
  ...
end 

这将创建一个具有随机超类的类。只是为了说明Ruby没有声明,只有可执行语句。

所以没有不执行Ruby文件的事情。 loadrequire之间的区别如您所述,后者跟踪所有加载的文件以避免重新加载它们。

PS,另一个例子

ruby --dump insns -e 'def example; end'
== disasm: <RubyVM::InstructionSequence:<main>@-e>======================
0000 trace            1                                               (   1)
0002 putspecialobject 1
0004 putspecialobject 2
0006 putobject        :example
0008 putiseq          example
0010 opt_send_without_block <callinfo!mid:core#define_method, argc:3, ARGS_SIMPLE>
0012 leave            
== disasm: <RubyVM::InstructionSequence:example@-e>=====================
0000 trace            8                                               (   1)
0002 putnil           
0003 trace            16                                              (   1)
0005 leave            

正如您所看到的,def example; end是一个语句,并在内部调用define_method方法。所以def只是方法调用的语法糖。