2008-09-04 91 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" 
    
    相关问题