jjzjj

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

coder 2025-04-08 原文

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 - 为什么 Ruby setter 需要 "self."类内的资格?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    3. Ruby 解析字符串 - 2

      我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

    4. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    5. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    6. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    7. ruby-on-rails - rails : keeping DRY with ActiveRecord models that share similar complex attributes - 2

      这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby​​类,但是我如何得到ActiveRecord关联这个类模型

    8. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    9. ruby - 其他文件中的 Rake 任务 - 2

      我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

    10. ruby - 如何在 Ruby 中顺序创建 PI - 2

      出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

    随机推荐