我有一個Ruby的文件名爲test.rb爲什麼我不能在Ruby中訪問方法中的局部變量?
ff="ff"
def test
puts ff
end
我執行它,遇到錯誤:
test.rb:3:in `test': undefined local variable or method `ff' for main:Object (NameError)
什麼是這個原因?有沒有解釋它的文檔?
我有一個Ruby的文件名爲test.rb爲什麼我不能在Ruby中訪問方法中的局部變量?
ff="ff"
def test
puts ff
end
我執行它,遇到錯誤:
test.rb:3:in `test': undefined local variable or method `ff' for main:Object (NameError)
什麼是這個原因?有沒有解釋它的文檔?
原因ff
在test
方法定義中不可訪問,只是方法(使用關鍵字def
創建)創建一個新的作用域。與分別使用class
和module
關鍵字定義類和模塊相同。
main
(頂層對象)的作用幾乎完全與這種情況下的範圍問題無關。
需要注意的是,如果你想你的test
方法訪問在定義範圍內定義的當地人,然後使用define_method
(或在您的情況下,define_singleton_method
法),在這裏看到:
ff = "hi"
define_singleton_method("test") { ff }
test #=> "hi"
與def
關鍵字不同,define_method
方法家族不創建新的作用域,而是關閉當前作用域,捕獲所有局部變量。
使用@ff
原因由@soup給出下面的例子中的工作,是不是main
是某種「特例」這只是在頂級定義的伊娃是main
伊娃,所以是一個訪問方法調用main
。
但是,test
方法與main
的關係是什麼?它不是的方法只是main
本身 - 它實際上是Object
類中定義的私有實例方法。這意味着test
方法將可用(作爲私有方法)幾乎在您的ruby程序中的每個對象。在頂層(main
)定義的所有方法實際上定義爲Object
類中的私有實例方法。
有關紅寶石頂級的更多信息,請參閱這篇文章:http://banisterfiend.wordpress.com/2010/11/23/what-is-the-ruby-top-level/
Ruby範圍既簡單又複雜。
首先,你必須記住,一切都是一個對象,一切都有一個範圍。
直接回答你的問題,main
是一個對象,這樣當你寫你定義的對象main
上的方法觀察在PYR/IRB def x...
:
# note the error describes
[1] pry(main)> main 'main:Object'
NameError: undefined local variable or method 'main' for main:Object
from (pry):1:in '<main>'
# self is the current object, which is main
[2] pry(main)> self
=> main
# note main is an object of type Object
[3] pry(main)> self.class
=> Object
# main has methods
[4] pry(main)> self.methods
=> [:to_s, :public, etc etc]
所以,當你寫
ff = "ff"
def test
puts ff
end
你真正做的是
class main
ff = "ff"
def test
puts ff
end
end
由於ff
超出範圍,所以不起作用。要解決這個問題,你必須將ff
變成一個實例變量,所以在@
的前面加上它的名字。下面的工作:
@ff = "ff"
def test
puts @ff
end
test
需要注意的是,這似乎是爲main
比普通班的特殊情況,請參閱下文。
如果我們有我們自己的測試類:
class Test1
ff = "ff"
def test
puts ff
end
end
Test1.new.test # undefined variable/method 'ff' error
因爲ff
沒有在正確的範圍定義爲預期這將失敗。它的作用範圍在於解析器執行我們的類聲明時。
所以讓我們嘗試上述修正:
class Test1Fixed
@ff = "ff"
def test
puts @ff
end
end
Test1Fixed.new.test # results in blank line
那怪異。
讓我們添加這個方法:
def ff?
puts "ff is: #{@ff.nil? ? "nil" : "not nill"}"
end
Test1Fixed.new.ff? # => ff is: nil
爲什麼@ff零?
下可能使這更清楚:
class Test2
puts "Where am i?"
@instance = "instance"
def initialize
puts "Initalize"
end
puts "pants on"
def test
puts "This will NOT output 'instance': #{@instance}"
end
def self.class_test
puts "This WILL output 'instance': #{@instance}"
end
end
puts "Creating new Test2 Object"
t = Test2.new
puts "Calling test on Test2 Object"
t.test
puts "Calling class_test on Test2 Class object"
Test2.class_test
運行此,我們得到以下的輸出:
$ ruby scope.rb
Where am i?
pants on
Creating new Test2 Object
Initalize
Calling test on Test2 Object
This will NOT output 'instance':
Calling class_test on Test2 Class object
This WILL output 'instance': instance
正如你所看到的,interperter運行在我們的類聲明的順序,只需像其他地方一樣,並輸出我們的puts
聲明。當我們開始調用方法時,這會變得更有趣。編寫@instance = ...
與編寫self.instance = ...
相同,所以你可以猜測我們定義的實例在哪裏?是的,在Test2類對象(不是Test2對象)。
這就是爲什麼當我們調用test
,沒有什麼是outputed,因爲裏面test
,self
指實例化Test2
對象,而不是Test2 class object
(這是我們設置@instance是什麼!)。這就是爲什麼你在initialize
裏設置實例變量的原因,其中self
將指向實際的對象。
當我們通過self.class_test
定義一個類方法,然後在Test2類對象(Test2.class_test
)上調用該方法時,我們可以看到預期的輸出,因爲在該範圍內定義了@instance
。
希望這是有道理的。
http://rubykoans.com/範圍部分可能有助於鞏固這些知識。
在紅寶石中,沒有印記的名稱總是具有「本地」範圍。 Ruby使用詞法作用域,因此在一個方法中,名稱始終僅指那個方法。
其他範圍是全局的,實例和類。這裏有一個很好的文檔: http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators#Scope
有幾種方法可以解決您的問題;我最喜歡的是通過被印刷爲參數的事情:
ff = "ff"
def test(ff)
puts ff
end
更可能的是,你會被封裝你在一個班做什麼,用一個實例變量。
你也可以使用一個全局變量($ ff),但這種方式的瘋狂謊言。
如果您只想在當前文件中共享變量,最好使用'@ a'而不是'$ a',因爲它可以防止名稱空間污染延伸。 –
Why can't I access a local variable inside a method in Ruby?
因爲它是一個局部變量。局部變量侷限於它們定義的範圍。這就是爲什麼它們被稱爲「局部變量」的原因。
在這種情況下,您所定義的腳本範圍的局部變量,因此它在腳本範圍內可見,並無處。
感謝您的支持。我明白主要是如何工作。酷'MyObject.new .__發送__(:測試)'工作! (雖然可能沒有用)。我試過解釋'@ ff' var是類的成員,因此爲什麼它是nil,'Test2'應該通過它的輸出來解釋這個(「'will /將不會輸出'instance''',這取決於你是否調用'test'或'class_test'),但也許我不是特別清楚。另外如果你寫/開始撬,這是非常酷的兄弟! – Soup
@soup更新了答案,以反映你做了正確的解釋'@ ff',抱歉:) Thx再撬,很高興你喜歡它:) – horseyguy