ruby - 为什么 Ruby setter 需要 "self."类内的资格?

标签 ruby

Ruby setter——无论是由 (c)attr_accessor 创建的或手动——似乎是唯一需要的方法 self.在类本身中访问时的限定。这似乎让 Ruby 在语言世界中独树一帜:

  • 所有方法都需要self/this (像 Perl,我认为是 Javascript)
  • 没有方法需要 self/this是(C#,Java)
  • 只有 setter 需要 self/this ( ruby ?)

  • 最好的比较是 C# 与 Ruby,因为这两种语言都支持在语法上像类实例变量一样工作的访问器方法:foo.x = y , y = foo.x . C# 称它们为属性。

    这是一个简单的例子; Ruby 和 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 =()它失败了(Linux 和 OS X 上的 Ruby 1.8.6)。现在 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();
      }
    }
    

    问题:这是真的吗?除了需要 self 的 setter 之外,还有其他场合吗?即,是否还有其他场合无法在没有 self 的情况下调用 Ruby 方法?

    肯定有很多情况需要 self 。这不是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
    

    这是模棱两可的——这是一个方法调用还是一个新的局部变量赋值?

    @迈克·斯通

    嗨!我理解并感谢你提出的观点和你的
    例子很棒。相信我,如果我有足够的声誉,
    我会投票赞成你的回应。然而我们仍然不同意:
  • 关于语义问题,以及
  • 关于事实的中心点

  • 首先我声称,并非没有讽刺意味,我们正在进行一场关于
    “歧义”的意思。

    当涉及到解析和编程语言语义(主题
    这个问题),你肯定会承认这个概念的广泛性
    '歧义'。让我们采用一些随机符号:
  • 歧义:词法歧义(lex 必须“向前看”)
  • 歧义:语法歧义(yacc 必须遵循解析树分析)
  • AMBIGUOUS:在执行的那一刻就知道一切的模糊

  • (而且 2-3 之间也有垃圾)。所有这些类别都由
    收集更多上下文信息,越来越全局化。所以当你
    说,

    "qwerty = 4" is UNAMBIGUOUS in C# when there is no variable defined...



    我完全同意。但出于同样的原因,我是说

    "qwerty = 4" is un-Ambiguous in ruby (as it now exists)

    "qwerty = 4" is Ambiguous in C#



    而且我们还没有相互矛盾。最后,这是我们真正的地方
    不同意: ruby 可以或不能在没有任何进一步的情况下实现
    语言构造使得,

    For "qwerty = 4," ruby UNAMBIGUOUSLY invokes an existing setter if there
    is no local variable defined



    你说不。我说是;另一个 ruby​​ 可能存在,其行为与
    各方面的电流,除了“qwerty = 4”定义了一个新的
    当没有 setter 和 local 存在时变量,如果有,则调用 setter
    存在,如果存在,则分配给本地。我完全接受我
    可能是错的。事实上,我可能错的原因会很有趣。

    让我解释。

    想象一下,您正在编写一种新的 OO 语言,其中的访问器方法看起来像
    像实例变量(像 ruby​​ 和 C#)。你可能会开始
    概念语法类似于:
      var = expr    // assignment
      method = expr // setter method invocation
    

    但是解析器-编译器(甚至不是运行时)会呕吐,因为即使在
    所有输入都被理解了,无法知道哪种语法是相关的。
    你所面临的经典选择。我不能确定细节,但是
    基本上 ruby​​ 是这样做的:
      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#,“稍后”仍处于编译时。

    我确信 ruby​​ 可以做同样的事情,但“稍后”必须在运行时,因为
    正如本指出的那样,在执行语句之前您不知道哪种情况
    适用。

    我的问题从来就不是“我真的需要‘自我’吗?”或者是什么
    正在避免潜在的歧义?”相反,我想知道这是为什么
    做了什么特别的选择?也许这不是性能。也许它只是得到了这份工作
    完成,或者被认为最好总是允许 1-liner local 覆盖
    方法(一种非常罕见的情况要求)...

    但我有点建议最有活力的语言可能是那种
    将这个决定推迟最久,并根据最上下文选择语义
    信息:所以如果你没有本地并且你定义了一个setter,它会使用setter。是不是
    这就是为什么我们喜欢 ruby​​、smalltalk、objc,因为方法调用是在运行时决定的,
    提供最大的表现力?

    最佳答案

    这里要记住的重要一点是,Ruby 方法可以在任何时候(取消)定义,因此为了智能地解决歧义,每个赋值都需要运行代码来检查当时是否存在具有赋值名称的方法的任务。

    关于ruby - 为什么 Ruby setter 需要 "self."类内的资格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44715/

    相关文章:

    ruby-on-rails - 如何创建一个包含两个带逗号 gem 模型的 CSV 文件?

    ruby - vagrant用数学循环设置IP地址

    ruby - Rails -- 理解 db :migrate

    ruby-on-rails - 使用 HAML 而不是 ERB 导致测试失败

    ruby - 记录到 rake 的跟踪日志

    javascript - 将 Rails DB as_json.to_json 嵌入到 Javascript 中不起作用。 (变成“东西”)

    ruby-on-rails - 三元运算符 ruby

    ruby-on-rails - 在 RSpec 单元测试中模拟竞争条件

    ruby - 全新应用程序服务器上的 Rails 'parse_query' 错误

    ruby - 使用 ElasticSearch 时的 Logstash 错误消息输出 = >"Failed to flush outgoing items"