2008-09-04 94 views
59

Ruby setter(無論是由(c)attr_accessor創建的還是手動創建的)似乎是在類自身內部進行訪問時唯一需要self.限定的方法。這似乎把紅寶石單獨的語言世界:爲什麼Ruby制定者需要「自我」。在課堂上的資格?

  • 所有方法都需要self/this(如Perl,我認爲JavaScript)的
  • 沒有方法需要self/this是(C#,Java的)
  • 只有制定者需要self/this(紅寶石?)

最好的比較是C#VS紅寶石,因爲這兩種語言都支持這句法工作就像類斯塔存取方法nce變量:foo.x = yy = foo.x。 C#調用它們的屬性。

下面是一個簡單的例子;在紅寶石同一程序然後C#:

class A 
    def qwerty; @q; end     # manual getter 
    def qwerty=(value); @q = value; end # manual setter, but attr_accessor is same 
    def asdf; self.qwerty = 4; end  # "self." is necessary in ruby? 
    def xxx; asdf; end     # we can invoke nonsetters w/o "self." 
    def dump; puts "qwerty = #{qwerty}"; end 
end 

a = A.new 
a.xxx 
a.dump 

帶走self.qwerty =()和失敗(紅寶石1.8.6在Linux & OS X)。現在C#:

using System; 

public class A { 
    public A() {} 
    int q; 
    public int qwerty { 
    get { return q; } 
    set { q = value; } 
    } 
    public void asdf() { qwerty = 4; } // C# setters work w/o "this." 
    public void xxx() { asdf(); }  // are just like other methods 
    public void dump() { Console.WriteLine("qwerty = {0}", qwerty); } 
} 

public class Test { 
    public static void Main() { 
    A a = new A(); 
    a.xxx(); 
    a.dump(); 
    } 
} 

問題:這是真的嗎?除了制定者之外,還有其他需要自我的場合嗎?也就是說,Ruby方法不能調用而沒有自己嗎?

肯定有很多情況下,自我變成必要的。這不是Ruby唯一的,只是要清楚:

using System; 

public class A { 
    public A() {} 
    public int test { get { return 4; }} 
    public int useVariable() { 
    int test = 5; 
    return test; 
    } 
    public int useMethod() { 
    int test = 5; 
    return this.test; 
    } 
} 

public class Test { 
    public static void Main() { 
    A a = new A(); 
    Console.WriteLine("{0}", a.useVariable()); // prints 5 
    Console.WriteLine("{0}", a.useMethod()); // prints 4 
    } 
} 

相同的歧義以相同的方式解決。不過,雖然微妙,我問在哪裏

  • 被定義的方法的情況下,和
  • 沒有局部變量已經被定義,並

我們遇到

qwerty = 4 

這是模棱兩可的 - 這是一個方法調用還是一個新的局部變量賦值?


@Mike石

嗨!我理解並欣賞您提出的觀點,並且您的示例很棒。相信我,當我說,如果我有足夠的聲譽, 我會投你的迴應。然而,我們仍然不同意:

  • 語義上的問題,並在事實上

首先我要求,不無諷刺,我們具有關於語義爭論的中心點

  • '含糊不清'的含義 。

    當談到解析和編程語言語義(這個問題的主題 ),當然你會承認廣泛的概念 '歧義'。讓我們只採用一些隨機的符號:

    1. 曖昧:詞彙歧義(法必須「向前看」)
    2. 曖昧:歧義(YACC必須按照解析樹分析)
    3. 含糊:歧義知道一切在執行的時刻

    (並且在2-3之間也有垃圾)。所有這些類別均由 解決,收集更多上下文信息,在全球範圍內看起來越來越多。所以,當你 說,

    「QWERTY = 4」 是在C# 明確的時候沒有定義的變量...

    我不能同意。但是,同樣的道理,我說

    「QWERTY = 4」 是紅寶石 未明確(因爲它現在已經存在)

    「QWERTY = 4」 是在C#不明確

    而且我們還沒有相互矛盾。最後,這就是我們真正 不同意:無論是紅寶石可以或不可以在沒有任何進一步的 語言結構實現,這樣,

    對於「QWERTY = 4,」紅寶石明確 調用現有的二傳手,如果有
    是沒有定義的局部變量

    你說不。我說是;另一個紅寶石可能存在,其行爲與 完全相同,除外「qwerty = 4」定義了一個新的 變量,當沒有setter和本地存在時,它調用setter,如果一個 存在,並且它分配給本地(如果存在)。我完全同意我可能是錯誤的 。事實上,我可能會犯錯的原因很有意思。

    讓我解釋一下。

    想象一下,您正在編寫一個新的面向對象方法,使用像實例變量(如ruby & C#)的 。你可能有 概念語法像開始:

    var = expr // assignment 
        method = expr // setter method invocation 
    

    但是解析器編譯器(甚至不運行時)會吐的,因爲即使在 所有的輸入grokked有沒有辦法知道哪些語法相關。 您正面臨着哪一個經典選擇。我不能肯定的細節,但 基本上紅寶石做到這一點:

    var = expr // assignment (new or existing) 
        // method = expr, disallow setter method invocation without . 
    

    ,這就是爲什麼它是聯合國曖昧,而和C#這樣處理:

    symbol = expr // push 'symbol=' onto parse tree and decide later 
           // if local variable is def'd somewhere in scope: assignment 
           // else if a setter is def'd in scope: invocation 
    

    對於C#,「以後'仍在編譯時。

    我敢肯定,紅寶石可以做同樣的事情,但'稍後'必須在運行時,因爲 明確指出,你不知道,直到執行聲明 適用。

    我的問題從來沒有打算表示「我真的需要'自我'嗎?」?或「什麼 潛在的歧義正在被避免?」相反,我想知道爲什麼這個 做出了特別的選擇?也許這不是性能。也許它只是完成了 的工作,或者它被認爲是最好的總是允許1班輪本地覆蓋 方法(一個非常罕見的情況下要求)...

    但我有點暗示,最動態的語言可能是 推遲這個決定的時間最長的語言,並且選擇基於最上下文 信息的語義:所以如果你沒有本地並且你定義了一個setter,它會使用setter。這不是 這就是爲什麼我們喜歡ruby,smalltalk,objc,因爲方法調用在運行時決定, 提供最大的表現力?

  • +0

    PHP在訪問實例變量時也需要`$ this->`。這讓我一直在旅行。 – Chloe 2014-01-01 23:50:55

    +0

    只有類方法需要顯式接收器,而不是實例方法。 – 2014-10-01 23:52:17

    +0

    我同意 - 我也不喜歡這種解決amibuity的方法。違反最少驚喜的原則。 – Dogweather 2016-01-17 22:14:18

    回答

    17

    這裏要記住的重要一點是,Ruby方法可以在任何時候被(未)定義,所以爲了智能地解決歧義問題,每個分配都需要運行代碼來檢查是否存在一個方法,在分配時的名字。

    75

    嗯,我認爲這是這種情況的原因是因爲qwerty = 4是不明確的 - 您是否定義了一個名爲qwerty的新變量或調用setter? Ruby通過說它會創建一個新變量來解決這個模糊問題,因此需要self.

    在這裏你需要self.另一種情況:

    class A 
        def test 
        4 
        end 
        def use_variable 
        test = 5 
        test 
        end 
        def use_method 
        test = 5 
        self.test 
        end 
    end 
    a = A.new 
    a.use_variable # returns 5 
    a.use_method # returns 4 
    

    正如你所看到的,獲得test是模糊的,因此需要的self.。另外,這就是爲什麼C#示例實際上並不是一個好的比較,因爲您使用setter時以明確的方式定義變量。如果您在C#中定義了一個與訪問器名稱相同的變量,則需要使用this.來限定對訪問器的調用,就像Ruby案例一樣。

    +0

    這個解釋非常好 – 2017-06-29 09:52:50

    13

    因爲否則就不可能在方法內部設置局部變量。 variable = some_value含糊不清。例如:

    class ExampleClass 
        attr_reader :last_set 
        def method_missing(name, *args) 
        if name.to_s =~ /=$/ 
         @last_set = args.first 
        else 
         super 
        end 
        end 
    
        def some_method 
        some_variable = 5 # Set a local variable? Or call method_missing? 
        puts some_variable 
        end 
    end 
    

    如果self是不需要制定者,some_method將提高NameError: undefined local variable or method 'some_variable'。但是,該方法的工作原理如下:

    example = ExampleClass.new 
    example.blah = 'Some text' 
    example.last_set #=> "Some text" 
    example.some_method # prints "5" 
    example.last_set #=> "Some text" 
    
    相關問題