【问题标题】:What scope does an "at" sigil (@) give within Ruby functions?在 Ruby 函数中,“at”符号 (@) 的作用域是什么?
【发布时间】:2009-05-08 00:15:08
【问题描述】:

自从我上次进行 Ruby 编程以来已经有一段时间了——查看其他人的代码,我在一个函数中看到了 @ sigil(不是一个方法——在任何类定义之外) ,我理解它的范围是实例成员。

模块是函数中隐含的self吗?

【问题讨论】:

    标签: ruby scope sigils


    【解决方案1】:

    在顶级函数中(实际上仍然是一个方法),您处于一个有点奇怪的地方:全局“主”空间(请参阅运行 irb 时的提示,或尝试查看内部的 self这样的函数),而且这些函数也被定义为Object类中的私有方法。

    $ cat foo
    def foo
      p self
      p self.class
      puts 'foo'
    end
    
    foo
    Object.foo
    
    $ ruby foo
    main
    Object
    foo
    foo:8: private method `foo' called for Object:Class (NoMethodError)
    $ 
    

    您可以通过显式声明这些方法public 来绕过这个问题,但我不确定我是否喜欢这个!奇怪的是,如果你在irb 中定义了一个顶级方法,那么你可以通过类方法Object#foo 调用它,而无需将其声明为public。

    所以这是一种“隐含的主命名空间入侵Object(但嘘不要告诉任何人)”。在顶级函数中定义的@foo 在 Object 中可用,作为普通的旧属性。有点。如果您的顶级方法设置 @foo 并且您在没有作用域的情况下调用它,则它在类特征 main 命名空间中声明,但如果您通过 Object 调用类方法,则 @foo 出现在Object.

    另一个例子:

    public
    def set_foo
      @foo = 'foo'
    end
    
    def get_foo
      @foo
    end
    
    def Object.get_foo_again
      @foo
    end
    
    set_foo
    p get_foo
    p Object.get_foo_again
    
    Object.set_foo
    p Object.get_foo_again
    

    给予

    "foo"  # @foo set in main
    nil    # @foo nil in Object  
    "foo"  # @foo in Object
    

    反之亦然。

    【讨论】:

      【解决方案2】:

      认为这是“一个函数,而不是一个方法”的假设是错误的。所有 Ruby 代码都出现在某个对象的上下文中。 “全局”上下文是一个名为 main 的对象(如果您不相信,请尝试 ruby -e "puts self")。在顶层范围内定义的方法成为 Object 的实例方法。这意味着该方法将在任何地方可用,self(以及实例变量所属的上下文)取决于调用方法的位置

      【讨论】:

      • 好的,模块级函数中的@ident 是 $ident 的另一种说法吗?
      • 不,它设置模块的@ident 实例变量(请记住,在 Ruby 中,模块也是一个对象,并且可以有自己的 ivars)。 "@ident = something" 将设置当前任何 "self" 的 @ident 实例变量。
      • 好的,所以全局变量是真正的全局变量(绑定到解释器),不限于任何给定模块的范围?
      • 那么在模块级函数中使用@ident 来制作模块范围的标识符是常见的做法吗?我认为在模块开始时预先声明它们会更直接。
      【解决方案3】:

      我认为它的范围是一个模块。

      【讨论】:

        【解决方案4】:

        @ 使变量成为实例变量。听起来它不是显式声明的类的一部分,因此正如 Chuck 指出的那样,它将在主对象中可用。通过示例更容易说明:

        $ irb
        irb(main):001:0> @var = 1
        => 1
        irb(main):002:0> class New
        irb(main):003:1>   def test
        irb(main):004:2>     puts @var
        irb(main):005:2>   end
        irb(main):006:1> end
        => nil
        irb(main):007:0> test = New.new
        => #<New:0xb7ccbc14>
        irb(main):008:0> test.test
        nil
        => nil
        irb(main):009:0> def test2
        irb(main):010:1>   puts @var
        irb(main):011:1> end
        => nil
        irb(main):012:0> test2
        1
        => nil
        

        【讨论】:

          猜你喜欢
          • 2022-12-02
          • 2011-09-17
          • 2022-04-26
          • 2011-02-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多