Ruby中require, require_relative,load,include的用法和區(qū)別

引言

在Ruby中,當(dāng)我們想引用某些庫或者其它文件中定義的類和方法時候,會使用 require 或者require_relative,load,include

那么,它們兩個有什么區(qū)別? Ruby怎么知道要去哪里搜索,也就是,Ruby的require的默認(rèn)搜索路徑是什么?

require

require是Ruby中用的最多的,它通常用來導(dǎo)入系統(tǒng)庫,還有我們用gem安裝的三方庫.我們自己工程中的文件之間的相互引用,也是用的它.

require的用法

require 'commander/import'
require 'terminal-table'
require 'term/ansicolor'
require 'csv'

require 'cupertino'

Ruby會在ruby所對應(yīng)的gem庫的搜索路徑去尋找指定的文件,什么意思呢,就是說,如果你系統(tǒng)上有多個ruby,那么你用的哪個ruby來跑,那么其搜索使用的就是對應(yīng)版本的ruby的gem的搜索庫

ruquire的搜索路徑在全局變量 :(這個全局變量名字就是:,帶冒號的)中,:也等價于LOAD_PATH.

當(dāng)我們在ruby中,想使用另外一個ruby中的內(nèi)容,需要用require關(guān)鍵字來加載另外的ruby文件中的內(nèi)容 require會在預(yù)設(shè)的 :(等價于LOAD_PATH)中去查找對應(yīng)的文件

例如,在我的電腦上,默認(rèn)的全局$:的路徑是

?  testRuby ruby -e 'puts $:'
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/site_ruby/2.6.0
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/site_ruby/2.6.0/x86_64-darwin18
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/site_ruby
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/vendor_ruby/2.6.0
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/vendor_ruby/2.6.0/x86_64-darwin18
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/vendor_ruby
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/x86_64-darwin18

可能你會覺得奇怪,上面輸出的路徑似乎并沒有包含我們使用gem install安裝的三方庫.我們用命令輸出下gem的安裝目錄

?   gem env | grep -A2 'GEM PATHS'
  - GEM PATHS:
     - /Users/yohunl/.rvm/gems/ruby-2.6.0
     - /Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/gems/2.6.0

其實這是因為,用戶gem的安裝目錄,是在require執(zhí)行的時候,動態(tài)先添加到$:中去的.
我們可以打開irb來驗證一下

old_load_path = $LOAD_PATH.dup
require 'cocoapods'
new_load_path = $LOAD_PATH.dup

從輸出的結(jié)果可以看出來,當(dāng)執(zhí)行了一個require后,$:的結(jié)果增加了很多,差不多增加了20個....

這也就驗證了,在第一次執(zhí)行到require的時候,require內(nèi)部會先添加路徑.

目前,require已經(jīng)支持相對路徑了!!!!很多文章中說的不支持,已經(jīng)是過去式了.

例如 在我們目錄下下有兩個文件 a.rb 和b.rb

.
├── a.rb
└── b.rb

由于require的搜索路徑并沒有當(dāng)前目錄,所以直接 require "b"是不行的.

有以下幾種方式:

require "./b" #采用相對路徑

或者

$: << File.dirname(__FILE__)
require "b"

或者

$LOAD_PATH.push File.dirname(__FILE__)
require "b"

或者

$LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__))  

require "b"

或者

require File.dirname(__FILE__) + '/b.rb'

或者

require File.expand_path('../b.rb', __FILE__)

那么,如果我們想包含一個文件夾下有所的文件呢?
最好的方法是將目錄添加到加載路徑,然后require每個文件的基本名稱.當(dāng)然你也可以用如下的命令來加載文件夾下所有的文件

Dir["/path/to/directory/*.rb"].each {|file| require file }

另外,有人寫了一個簡單的require_all來實現(xiàn)這個功能,可以用

gem install require_all

來安裝它

require_relative

require_relative的調(diào)用是相對路徑。如當(dāng)前文件夾下存在一個名為foo.rb的文件時,調(diào)用的方式為require_relative 'foo'。它不能調(diào)用$LOAD_PATH中的包

load

load也是加載一個文件,它與require_relative的區(qū)別是:

require_relative多次加載同一文件時,只會加載一次;load每一次調(diào)用都會重加載該文件。

include

我們平時用的很少
Ruby Require VS Load VS Include VS Extend 有詳細(xì)的介紹,這里摘錄關(guān)鍵的部分

在一個模塊中,可能會有很多膠水代碼,也就是說類A中有一些函數(shù),和類B中一些函數(shù)的實現(xiàn)是 一模一樣的,這個時候,就可以把 那部分一樣的函數(shù)提取出來,寫在module中,然后在每個類用include這個module
就很簡便在這個類中插入了module中的這幾個方法了,避免了拷貝型的重復(fù)工作

module Log 
  def class_type
    "This class is of type: #{self.class}"
  end
end

class TestClass 
  include Log 
end

tc = TestClass.new.class_type
puts tc #This class is of type: TestClass
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容