class Hello
@hello = "hello"
def display
puts @hello
end
end
h = Hello.new
h.display
我創建了上面的類。它不打印任何東西。我認爲實例變量@hello是在類聲明期間設置的。但是當我調用顯示方法時,輸出是'零'。什麼是正確的方法來做到這一點?什麼時候Ruby實例變量被設置?
class Hello
@hello = "hello"
def display
puts @hello
end
end
h = Hello.new
h.display
我創建了上面的類。它不打印任何東西。我認爲實例變量@hello是在類聲明期間設置的。但是當我調用顯示方法時,輸出是'零'。什麼是正確的方法來做到這一點?什麼時候Ruby實例變量被設置?
實例變量可能是一個有點混亂第一學習Ruby的時候,特別是如果你習慣於像Java另一種面向對象的語言。
你不能簡單地聲明一個實例變量。
除了帶有@符號前綴的符號之外,關於ruby中實例變量最重要的知識之一是,它們在第一次被分配到時會跳入生命中。
class Hello
def create_some_state
@hello = "hello"
end
end
h = Hello.new
p h.instance_variables
h.create_some_state
p h.instance_variables
# Output
[]
["@hello"]
您可以使用方法Object#instance_variables
列出對象的所有實例變量。
您通常會在initialize方法中「聲明」並初始化所有實例變量。清楚記錄哪些實例變量應公開可用的另一種方法是使用模塊方法attr_accessor
(讀取/寫入),attr_writer
(寫入)和attr_reader
(讀取)。這些方法將爲列出的實例變量合成不同的訪問器方法。
class Hello
attr_accessor :hello
end
h = Hello.new
p h.instance_variables
h.hello = "hello"
p h.instance_variables
# Output
[]
["@hello"]
仍然不創建,直到它的分配給使用合成的Hello#hello=
方法的實例變量。
另一個重要問題,如kch所述,您需要知道聲明類時激活的不同上下文。當聲明一個類時,最外面的範圍中的默認接收器(self)將是表示類本身的對象。因此,當您的代碼在類級別上分配給@hello
時,您的代碼將首先創建類實例變量。
裏面方法自將在其上調用方法的對象,所以你想在對象,這不存在名爲@hello
打印實例變量的值(注意,這是完全合法讀取一個不存在的實例變量)。
您需要添加一個initialize
方法:在你的代碼
class Hello
def initialize
@hello = "hello"
end
def display
puts @hello
end
end
h = Hello.new
h.display
第一@hello
被稱爲類實例變量。
它是常量Hello
指向的類對象的實例變量。 (和它是類Class
的一個實例。)
從技術上講,當你在class
範圍內,您的self
設置爲當前的類的對象,並@variables
涉及到當前的self
。男孩我吮吸解釋這些事情。
您可以通過觀看this collection of $5-each screencasts from The Pragmatic Programmers獲得所有這些和更多的澄清。
(或者你可以要求澄清在這裏,我會嘗試更新。)在紅寶石
一個很好的[文章](http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/)闡述了類級別的實例變量。 – 2014-02-14 12:10:20
在「The ruby programming language」一書中有一個明確的描述,閱讀它會很有幫助。我在這裏(由第7.1.16)粘貼:
類定義內,但一個 實例方法定義之外使用的實例變量是一個類實例變量。
class Point
# Initialize our class instance variables in the class definition itself
@n = 0 # How many points have been created
@totalX = 0 # The sum of all X coordinates
@totalY = 0 # The sum of all Y coordinates
def initialize(x,y) # Initialize method
@x,@y = x, y # Sets initial values for instance variables
end
def self.new(x,y) # Class method to create new Point objects
# Use the class instance variables in this class method to collect data
@n += 1 # Keep track of how many Points have been created
@totalX += x # Add these coordinates to the totals
@totalY += y
super # Invoke the real definition of new to create a Point
# More about super later in the chapter
end
# A class method to report the data we collected
def self.report
# Here we use the class instance variables in a class method
puts "Number of points created: #@n"
puts "Average X coordinate: #{@totalX.to_f/@n}"
puts "Average Y coordinate: #{@totalY.to_f/@n}"
end
end
......
因爲類的實例變量是類 對象只是實例變量,我們可以使用ATTR,attr_reader,和attr_accessor爲他們創造 存取方法。
class << self
attr_accessor :n, :totalX, :totalY
end
有了定義,我們可以參考我們的原始數據Point.n,Point.totalX和Point.totalY這些訪問。
我也建議你在看這些前綴類變量「@@」 - 這裏的一些示例代碼向您展示類和實例增值經銷商是不同的:
class Vars
@@classvar="foo"
def test
@instancevar="bar"
end
def Vars.show
puts "classvar: #{@@classvar}"
puts "instancevar: #{@instancevar}"
end
def instance_show
puts "classvar: #{@@classvar}"
puts "instancevar: #{@instancevar}"
end
end
# only shows classvar since we don't have an instance created
Vars::show
# create a class instance
vars = Vars.new
# instancevar still doesn't show b/c it hasn't been initialized
vars.instance_show
# initialize instancevar
vars.test
# now instancevar shows up as we expect
vars.instance_show
,我忘了有在Ruby中是一個「類實例變量」的概念。無論如何,OP的問題似乎令人費解,除了對kch答案的暗示之外,迄今爲止的任何答案都沒有真正解決:這是一個範圍問題。 (添加編輯:其實,sris的回答確實是在最後解決了這一點,但我會讓這個答案站在任何地方,因爲我認爲示例代碼可能對理解問題有幫助。)
In a Ruby類,從@
變量名可以指變量之一:或者一個實例變量或一個類實例變量,取決於其中在類它被稱爲。這是一個相當微妙的問題。
一個例子將闡明這一點。這裏有一個小的Ruby測試類(在IRB測試的所有代碼):
class T
@@class_variable = "BBQ"
@class_instance_variable_1 = "WTF"
@class_instance_variable_2 = "LOL"
def self.class_method
puts "@@class_variable == #{@@class_variable || 'nil'}"
puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
puts "@instance_variable == #{@instance_variable || 'nil'}"
end
def initialize
@instance_variable = "omg"
# The following line does not assign a value to the class instance variable,
# but actually declares an instance variable withthe same name!
@class_instance_variable_1 = "wtf"
puts "@@class_variable == #{@@class_variable || 'nil'}"
# The following two lines do not refer to the class instance variables,
# but to the instance variables with the same names.
puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
puts "@instance_variable == #{@instance_variable || 'nil'}"
end
def instance_method
puts "@@class_variable == #{@@class_variable || 'nil'}"
# The following two lines do not refer to the class instance variables,
# but to the instance variables with the same names.
puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
puts "@instance_variable == #{@instance_variable || 'nil'}"
end
end
我按照我以爲他們是命名變量,雖然這原來不是總是這樣的情況:
irb> T.class_method
@@class_variable == BBQ
@class_instance_variable_1 == WTF # the value of the class instance variable
@class_instance_variable_2 == LOL # the value of the class instance variable
@instance_variable == nil # does not exist in the class scope
=> nil
irb> t = T.new
@@class_variable == BBQ
@class_instance_variable_1 == wtf # the value of the instance variable
@class_instance_variable_2 == nil # the value of the instance variable
@instance_variable == omg
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf">
irb> t.instance_method
@@class_variable == BBQ
@class_instance_variable_1 == wtf # the value of the instance variable
@class_instance_variable_2 == nil # the value of the instance variable
@instance_variable == omg
=> nil
irb> T.class_method
@@class_variable == BBQ
@class_instance_variable_1 == WTF # the value of the class instance variable
@class_instance_variable_2 == LOL # the value of the class instance variable
@instance_variable == nil # does not exist in the class scope
=> nil
@@class_variable
和@instance_variable
總是按照您的預期行事:前者在類級別上定義,無論是在類方法中引用還是在實例方法中引用,都會在頂部保留指定給它的值。後者僅在類T
的對象中獲得值,因此在類方法中,它指的是值爲nil
的未知變量。
想象中名爲class_method
的類方法根據預期輸出@@class_variable
和兩個@class_instance_variable
的值,即在類的頂部初始化。但是,在實例方法initialize
和instance_method
,不同變量的同名被訪問,即實例變量,而不是類實例變量。
你可以看到,在initialize
方法分配並沒有影響到類實例變量@class_instance_variable_1
,因爲class_method
以後調用輸出其舊值,"WTF"
。相反,方法initialize
宣佈一個新的實例變量,一個是也命名(誤導性)@class_instance_variable_1
。分配給它的值"wtf"
由方法initialize
和instance_method
輸出。
的示例代碼變量@class_instance_variable_2
等同於原問題變量@hello
:它的聲明和初始化一個類的實例變量,但是當一個實例方法是指名稱的變量,它實際上看到實例變量名稱相同 - 從未聲明的一個,因此其值爲零。
你說「他們在第一次被分配時就會回到生活中」,然而OP顯示了一個比你的例子中的(明顯)任務更早的例子,並且遇到的問題是所述變量沒有因此而涌入生活。 – kaleidic 2014-07-30 21:21:23
@kaleidic沒錯。對於這個答案中沒有解決OP問題的upvotes數量,我感到有點困惑。實際上,類實例變量`@ hello` *在示例代碼的第2行出現,但問題在於它不是第4行指向的變量。進一步的細節見下面的答案。 – 2014-12-25 18:13:37