佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > Ruby常量查找路徑問(wèn)題深入研究

Ruby常量查找路徑問(wèn)題深入研究

熱門(mén)標(biāo)簽:客戶服務(wù) 呼叫中心市場(chǎng)需求 百度AI接口 Win7旗艦版 硅谷的囚徒呼叫中心 企業(yè)做大做強(qiáng) 電話運(yùn)營(yíng)中心 語(yǔ)音系統(tǒng)

Ruby 的常量查找路徑問(wèn)題是一直困擾我的一個(gè)問(wèn)題,在工作中遇到過(guò)好幾次,一直沒(méi)有徹底弄清楚到底為什么,最近在讀一本書(shū)《Ruby 元編程》,對(duì) Ruby 對(duì)象模型有了更深入的認(rèn)識(shí),另外讀了一篇 blog《Everything you ever wanted to know about constant lookup in Ruby》, 讓我總算把 Ruby 常量查找路徑這個(gè)問(wèn)題搞得比較清楚。

第一個(gè)遇到的問(wèn)題,我還曾經(jīng)在 Ruby-China 上發(fā)過(guò)帖。

復(fù)制代碼 代碼如下:

module M1
  CT = "ok"
end

class C1
  CK = "ck"
  include M1

  def self.method1
    puts self
    puts "#{CK} in method1"
    puts "#{CT} in method1"
  end

  class self
    def method2
      puts self
      puts "#{CK} in method1"
      puts "#{CT} in method2"
    end
  end
end

C1.method1
C1.method2

輸出結(jié)果是

復(fù)制代碼 代碼如下:

C1
ck in method1
ok in method1
C1
ck in method2
NameError: uninitialized constant Class::CT
    from (irb):16:in `method2'

這是我在重構(gòu)薄荷網(wǎng)代碼時(shí)候遇到的問(wèn)題,method1 和 method2 都是常見(jiàn)的類(lèi)方法的定義方面,我向來(lái)認(rèn)為它們是等價(jià)可替換的寫(xiě)法,但是從實(shí)際執(zhí)行的結(jié)果看,它們里面的常量查找路徑不一樣。

如果我把 M1 的定義改成下面的樣子:

復(fù)制代碼 代碼如下:

module M1
  def self.included(base)
    base.extend(self)
  end
  CT = "ok"
end

執(zhí)行結(jié)果是:

復(fù)制代碼 代碼如下:

C1
ck in method1
ok in method1
C1
ck in method2
ok in method2

還有一個(gè)問(wèn)題是也是經(jīng)常遇到的,抽象成問(wèn)題代碼如下:

復(fù)制代碼 代碼如下:

module A
  module M
    def a_method
      #...
    end
  end
end

class A::B
  include M
end

會(huì)報(bào)異常:

復(fù)制代碼 代碼如下:

NameError: uninitialized constant A::B::M
  from (irb):10:in `class:B>'

Ruby 常量查找時(shí)依據(jù)兩條路徑

A. Module.nesting
B. open class/module 的 ancestors

A 比 B 優(yōu)先,A 找不到了才到 B 中查找。

A.Module.nesting 的概念比較容易理解,它是指代碼位置的 module 嵌套情況,它是一個(gè)數(shù)組,從最內(nèi)層的嵌套一直到最外層的嵌套,如果沒(méi)有嵌套,數(shù)組為空。任何一處代碼位置都有 Module.nesting 值,可以通過(guò)下面的代碼打印出各個(gè)位置的 Module.nesting 值。

復(fù)制代碼 代碼如下:

p Module.nesting

module A
  module B
    p Module.nesting
    module C
      p Module.nesting
    end
  end
end

module A::B
  p Module.nesting
end

輸出是:

復(fù)制代碼 代碼如下:

[]
[A::B, A]
[A::B::C, A::B, A]
[A::B]

大家有沒(méi)有注意到,module A::B 這種快捷寫(xiě)法會(huì)導(dǎo)致 A 不在 Module.nesting 里,這就是上述第二個(gè)問(wèn)題的根源,因?yàn)?M 是 A module 下的常量,module A::B 寫(xiě)法導(dǎo)致不會(huì)查找 A::M。

說(shuō)完 A Module.nesting,再說(shuō)一下 B open class/module 的 ancestors,這個(gè)問(wèn)題相對(duì)復(fù)雜很多。簡(jiǎn)單的說(shuō),在 Ruby 代碼的任何位置,都有一個(gè) self 存在,同樣也有一個(gè) open class/module 存在,在模塊和類(lèi)定義處,它通常就是對(duì)應(yīng)的模塊和類(lèi),在方法內(nèi)部,它是方法對(duì)應(yīng)的類(lèi)。對(duì)于 ancestors,我們可以通過(guò)代碼位置 open class/module 的 ancestors 方法取得。

(備注:ancestors 在引入 singleton_class 概念之后變得有點(diǎn)復(fù)雜,如不清楚可參考《Ruby 元編程》)

上述第一個(gè)問(wèn)題: 在method1 中 A 是 [C1] open class/module 是 C1,所以 ancestors 是 [C1, M1, Object, Kernel, BasicObject] CK 在 A 可以找到,CT 在 B 可以找到。

method2 中 A 是 [C1] open class/module 是 C1 的 singleton_class , 所以 ancestors 是 [Class, Module, Object, Kernel, BasicObject] CK 在 A 可以找到,CT 在 A 和 B 都找不到。

對(duì)于

復(fù)制代碼 代碼如下:

module M1
  def self.included(base)
    base.extend(self)
  end
  CT = "ok"
end

可運(yùn)行,是因?yàn)檫@時(shí),在 method2 中,open class/module C1 的 singleton_class 擴(kuò)展了 M1,所以 ancestors 變成了 [M1, Class, Module, Object, Kernel, BasicObject]。

至此,這兩個(gè)困擾我多時(shí)的問(wèn)題終于徹底搞清楚了。這個(gè)過(guò)程給我的一個(gè)體會(huì)是:面對(duì)技術(shù)上的一些疑問(wèn),如果只是淺嘗輒止,是永遠(yuǎn)不能夠真正掌握它的,只有深入專(zhuān)研,透徹理解它的原理,才能夠真正掌握它,獲得真正的能力提升。

您可能感興趣的文章:
  • 在Ruby中查找和執(zhí)行方法
  • Ruby實(shí)現(xiàn)的最優(yōu)二叉查找樹(shù)算法
  • Ruby實(shí)現(xiàn)二分搜索(二分查找)算法的簡(jiǎn)單示例

標(biāo)簽:山西 安康 崇左 長(zhǎng)沙 濟(jì)南 山西 海南 喀什

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Ruby常量查找路徑問(wèn)題深入研究》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    安徽省| 班戈县| 湖南省| 教育| 柳河县| 连平县| 伊宁市| 河西区| 隆子县| 威远县| 柞水县| 铜梁县| 新野县| 临猗县| 陵川县| 洛宁县| 射阳县| 平乐县| 太仆寺旗| 婺源县| 西宁市| 文安县| 顺平县| 红桥区| 永年县| 名山县| 清新县| 保定市| 六盘水市| 石棉县| 高雄市| 芮城县| 增城市| 铁岭县| 嘉兴市| 曲靖市| 温宿县| 西林县| 灵璧县| 沙河市| 鹤壁市|