class X
def new()
@a = 1
end
def m(other)
@a == [email protected]
end
end
x = X.new()
y = X.new()
x.m(y)
但它沒有工作。
的錯誤信息是:
syntax error, unexpected tIVAR
如何從同一類比較兩個私有屬性呢?
class X
def new()
@a = 1
end
def m(other)
@a == [email protected]
end
end
x = X.new()
y = X.new()
x.m(y)
但它沒有工作。
的錯誤信息是:
syntax error, unexpected tIVAR
如何從同一類比較兩個私有屬性呢?
有幾種方法
消氣:
class X
attr_reader :a
def m(other)
a == other.a
end
end
instance_eval
:
class X
def m(other)
@a == other.instance_eval { @a }
end
end
instance_variable_get
:
class X
def m(other)
@a == other.instance_variable_get :@a
end
end
我不認爲紅寶石^ h作爲「朋友」或「受保護」訪問的概念,甚至「私人」很容易被盜用。使用getter會創建一個只讀屬性,而instance_eval意味着您必須知道實例變量的名稱,所以內涵是相似的。
瞭解'instance_eval'非常酷。起初我不相信你,所以我試了一下。像魅力一樣工作。我需要回頭去編程Ruby ......這是一種非常整齊的語言。 – 2009-12-02 03:19:11
它確實有'保護'方法。我更新了我的答案以證明這一點。 – 2009-12-02 03:23:46
哦,'保護'。這可能是最好的方法,因爲語法更自然。 – 2009-12-02 03:49:39
如果不使用instance_eval
選項(如@jleedev發佈),並選擇使用getter
方法,你仍然可以保持它protected
如果你想在Ruby protected
方法,只是做了下面創建一個只能從同一個類的對象讀取一個getter:
class X
def new()
@a = 1
end
def m(other)
@a == other.a
end
protected
def a
@a
end
end
x = X.new()
y = X.new()
x.m(y) # Returns true
x.a # Throws error
請注意,這裏有一個競爭條件:首先將attr_reader創建爲public,* then *,作爲單獨的步驟,它會被保護。另一個線程可以在這兩個步驟之間調用訪問器。我的編輯沒有這種競爭條件,因爲它切換到受保護*第一*和*然後*創建訪問者。無論如何,這個編輯仍然比原作者的版本更好,甚至不是有效的Ruby語法。 – 2009-12-04 10:00:44
@Jorg,感謝您收集冒號問題,但請不要重寫我的代碼。另外,同意其他編輯的競賽條件。我也回滾了他的變化。 – 2009-12-04 14:48:48
不知道,但是這可能幫助:類
之外,這是一個有點困難:
# Doesn't work:
irb -> [email protected]
SyntaxError: compile error
(irb):9: syntax error, unexpected tIVAR
from (irb):9
# But you can access it this way:
irb -> a.instance_variable_get(:@foo)
=> []
http://whynotwiki.com/Ruby_/_Variables_and_constants#Variable_scope.2Faccessibility
這兒已經出現了幾個很好的答案,立即解決問題,但我注意到你的代碼的其他一些作品是值得評論。 (他們中的大多數瑣碎,雖然)。
以下四個平凡的人,他們都涉及到編碼風格:
無論如何,這只是小東西。大的東西是這樣的:
def new
@a = 1
end
這並不不做你認爲它!這定義了一種稱爲X#new
和的方法方法稱爲X.new
的類方法!
你在這裏叫什麼:
x = X.new
是類方法叫new
,它已經從Class
類繼承。所以,你永遠不打電話給你的新方法,這意味着@a = 1
從來沒有得到執行,這意味着@a
永遠是不確定的,這意味着它將始終評估爲nil
這意味着self
的@a
和other
的@a
永遠是這意味着m
相同將永遠是true
!
你可能想要做的是提供一個構造函數,除了Ruby不具有有構造函數。 Ruby只使用工廠方法。
你真的想要覆蓋的方法是實例方法initialize
。現在你可能會問自己:「當我實際撥打類方法時,爲什麼我必須重寫實例方法initialize
?」new
?
好,施工對象在Ruby中是這樣工作的:對象建設分爲兩個階段,分配和初始化。分配是通過名爲allocate
的公共類方法完成的,該方法被定義爲類Class
的實例方法,並且通常是從不重寫。它只是爲對象分配內存空間並設置了幾個指針,但是此時對象並不是真正可用的。
這就是初始化程序進來的地方:它是一個名爲initialize
的實例方法,它設置對象的內部狀態並將其引入一個可以被其他對象使用的一致的,完全定義的狀態。
因此,爲了充分創建新的對象,你需要做的是這樣的:
x = X.allocate
x.initialize
[注:Objective-C的程序員可能會認識到這一點。]
然而,因爲它太容易忘記調用initialize
,並作爲一般規則的對象應該是施工後完全有效的,有一個叫Class#new
便利工廠方法,它完成了所有的工作,爲您和看起來像這樣:
class Class
def new(*args, &block)
obj = alloc
obj.initialize(*args, &block)
return obj
end
end
[注:實際上,initialize
是私有的,所以反射有可能被用來規避這樣的訪問限制:obj.send(:initialize, *args, &block)
]
最後,讓我解釋一下什麼錯在你m
會見HOD。 (其他人已經解釋瞭如何解決它。)
在Ruby中,沒有辦法(注意:在Ruby中,「沒有任何辦法」實際上轉換爲「總是有一種涉及反射的方式」)來訪問來自實例外部的實例變量。這就是爲什麼它畢竟被稱爲實例變量,因爲它屬於實例。這是Smalltalk的遺留問題:在Smalltalk中沒有可見性限制,全部方法是公共的。因此,實例變量只是在Smalltalk中進行封裝的方式,畢竟,封裝是面向對象的支柱之一。在Ruby中,有是可見性限制(例如,我們已經在上面看到過,例如),所以不必爲此隱藏實例變量。另一個原因是:統一訪問原則。
的UAP指出,如何使用功能應該是獨立於功能是如何實現的。因此,訪問功能應始終保持一致,即統一。原因是該功能的作者可以自由地更改該功能在內部的工作方式,而不會中斷該功能的用戶。換句話說,它是基本的模塊化。
這意味着例如獲取集合的大小應該始終相同,無論大小是否存儲在變量中,每次動態計算,第一次懶惰地計算,然後存儲在變量中,memoized管他呢。聽起來很明顯,但例如Java的得到這個錯誤:
obj.size # stored in a field
與
obj.getSize() # computed
紅寶石取出的簡單方法。在Ruby中,只有一個方式使用一項功能:發送消息。由於只有一種方式,訪問是統一的。
因此,長話短說:你根本無法訪問另一個實例的實例變量。你只能通過消息發送與該實例進行交互。這意味着另一個對象必須爲您提供一種訪問其實例變量的方法(在這種情況下至少爲protected
可見性),或者您必須違反該對象的封裝(並因此失去統一訪問,增加耦合並面臨未來風險破損)通過使用反射(在這種情況下instance_variable_get
)。
這是在其所有的榮耀:
#!/usr/bin/env ruby
class X
def initialize(a=1)
@a = a
end
def m(other)
@a == other.a
end
protected
attr_reader :a
end
require 'test/unit'
class TestX < Test::Unit::TestCase
def test_that_m_evaluates_to_true_when_passed_two_empty_xs
x, y = X.new, X.new
assert x.m(y)
end
def test_that_m_evaluates_to_true_when_passed_two_xs_with_equal_attributes
assert X.new('foo').m(X.new('foo'))
end
end
或者:
class X
def m(other)
@a == other.instance_variable_get(:@a)
end
end
其中這兩個你選擇的一個是personly口味的問題,我會說。該Set
類標準庫使用反射的版本,雖然它使用代替instance_eval
:。
class X
def m(other)
@a == other.instance_eval { @a }
end
end
(我不知道爲什麼也許instance_variable_get
根本沒當Set
寫有紅寶石是要在2月17歲時,stdlib中的一些內容是從最初的日子開始的。)
這是一個很棒的答案。我還沒有看到有人在很長一段時間內對這個問題付出了太多的努力。謝謝! – 2009-12-02 16:28:48
+1純粹的長度;-) – 2009-12-02 22:04:20
* ...你可能會問自己:「當我實際調用一個名爲'new'的類方法時,爲什麼我必須重寫一個名爲'initialize'的實例方法? 「*哈哈哈......我從來沒有問過我的那個。我以爲是*哦,所以它是'初始化'然後*。感謝你的回答,我每兩天閱讀一次(直到我得到它);) – OscarRyz 2009-12-04 22:47:28
簡短回答,當您調用實例變量時,不需要@。所以你需要other.a。 – 2009-12-02 16:29:30
@Chuck Vose:我想不是所有的答案都必須是正確的。我寫了'@a == other.a',解釋器說:'NoMethodError:未定義的方法'a'爲#' –
OscarRyz
2009-12-02 17:28:56
Ruby沒有屬性。 '@ a'是一個實例變量。 – 2012-03-28 08:01:03