2012-05-28 132 views

回答

12

原因fftest方法定義中不可訪問,只是方法(使用關鍵字def創建)創建一個新的作用域。與分別使用classmodule關鍵字定義類和模塊相同。

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/

+0

感謝您的支持。我明白主要是如何工作。酷'MyObject.new .__發送__(:測試)'工作! (雖然可能沒有用)。我試過解釋'@ ff' var是類的成員,因此爲什麼它是nil,'Test2'應該通過它的輸出來解釋這個(「'will /將不會輸出'instance''',這取決於你是否調用'test'或'class_test'),但也許我不是特別清楚。另外如果你寫/開始撬,這是非常酷的兄弟! – Soup

+0

@soup更新了答案,以反映你做了正確的解釋'@ ff',抱歉:) Thx再撬,很高興你喜歡它:) – horseyguy

9

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,因爲裏面testself指實例化Test2對象,而不是Test2 class object(這是我們設置@instance是什麼!)。這就是爲什麼你在initialize裏設置實例變量的原因,其中self將指向實際的對象。

當我們通過self.class_test定義一個類方法,然後在Test2類對象(Test2.class_test)上調用該方法時,我們可以看到預期的輸出,因爲在該範圍內定義了@instance

希望這是有道理的。

http://rubykoans.com/範圍部分可能有助於鞏固這些知識。

+0

不,當你在頂層(main)定義一個方法時,你實際上是在'Object'類本身定義了一個私有實例方法。在'main'上定義一個方法的唯一方法是在'main'的單例類中定義一個方法,la:'def self.hello;結束' – horseyguy

+0

其實,重新讀你的答案,其中大部分是完全錯誤的呵呵。 – horseyguy

+0

您可以編輯它或指向我可以瞭解更多信息的地方。我沒有研究過特定主題(主要等等,我研究過ruby範圍/對象,儘管可能不是最充分的程度),只是把我知道/認爲我知道的關於ruby對象/範圍的知識放在一起。 – Soup

2

在紅寶石中,沒有印記的名稱總是具有「本地」範圍。 Ruby使用詞法作用域,因此在一個方法中,名稱始終僅指那個方法。

其他範圍是全局的,實例和類。這裏有一個很好的文檔: http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators#Scope

有幾種方法可以解決您的問題;我最喜歡的是通過被印刷爲參數的事情:

ff = "ff" 
def test(ff) 
    puts ff 
end 

更可能的是,你會被封裝你在一個班做什麼,用一個實例變量。

你也可以使用一個全局變量($ ff),但這種方式的瘋狂謊言。

+0

如果您只想在當前文件中共享變量,最好使用'@ a'而不是'$ a',因爲它可以防止名稱空間污染延伸。 –

0

Why can't I access a local variable inside a method in Ruby?

因爲它是一個局部變量。局部變量侷限於它們定義的範圍。這就是爲什麼它們被稱爲「局部變量」的原因。

在這種情況下,您所定義的腳本範圍的局部變量,因此它在腳本範圍內可見,並無處

相關問題