【问题标题】:In Ruby, how does one add to an object a method with access to variables in outer scope?在 Ruby 中,如何向对象添加一种可以访问外部范围内变量的方法?
【发布时间】:2011-10-11 04:02:19
【问题描述】:

我是 Ruby 的新手。我正处于尝试用 Ruby 编写东西的阶段,但没有成功。

我正在尝试向一个对象添加一个方法——比如说,一个不起眼的数组。并非针对所有阵列,仅针对一个特定阵列。此方法必须能够访问外部范围内的变量。

我的理解是,我可以使用def 向对象添加方法,但该方法无法访问外部范围内的变量。为此,我需要使用 lambdaProc.new,但我看不到如何将 lambda/proc 作为属性“附加”到数组。

在 JavaScript 中这很简单,正如这个愚蠢的例子所展示的那样:

var x = 3
var array = [1, 2, 3, 4]

array.multiply_by_x = function() {
  var i = this.length
  while (i--) {
    this[i] *= x
  }
}

在 Ruby 中是否可以实现与上述类似的事情?

【问题讨论】:

    标签: ruby methods lambda lexical-scope


    【解决方案1】:

    这里不能使用 def 关键字来定义方法,因为它会引入另一个作用域。 如果您只想为特定对象定义一个方法,那么您必须在单例类中定义它。

    x = 3
    array = [1, 2, 3, 4]
    
    array.define_singleton_method(:multiply_by_x) do
      self.map!{|e| e * x }
    end
    

    但如果您使用的是 Ruby 1.8.x,则必须这样做:

    (class << array; self; end).send(:define_method, :multiply_by_x) do
      self.map!{|e| e * x }
    end
    

    注意:和这个问题无关,但是如果你想看different ways to define singleton methods.

    【讨论】:

    • singleton_classActiveSupport 中定义,所以在原版 1.8 中你必须这样做 (class &lt;&lt; array; self; end).send...
    • 太棒了!这正是我所追求的。现在做一些阅读以尝试了解它实际上在做什么以及为什么在这种情况下可以访问x
    • @davidchambers,Ruby 中的块在其他语言中是闭包。在此处阅读更多信息rubylearning.com/satishtalim/ruby_blocks.html
    【解决方案2】:

    Monkey-patching Array 会这样做,但它会为 Array 的所有实例这样做。

    class Array
      def multiply_by(x)
         self.map! {|n|
            n * x
         }
      end
    end
    

    如果您想任意将方法修补到现有对象上,我认为这是不可能的。

    您可以做的一件事是使用Hashlambda

    x = 3
    hash = {:array => [1,2,3]}
    hash[:multiply_by] = lambda {
       hash[:array].map! {|num|
          num * x
       }
    }
    

    然后您可以像这样调用multiply_by lambda:

    hash[:multiply_by].call
    

    【讨论】:

    • 您可以非常轻松地对现有对象进行猴子修补:a = []; def a.add_one; self&lt;&lt;1; end; p a.add_one
    • @steenslag 哇,真的好甜!
    【解决方案3】:

    我宁愿那样做:

    ary = [1, 2, 3, 4]
    
    def ary.multyply_by(x)
      self.map! {|e| e * x}
    end
    
    p ary.multyply_by 10
    

    附带说明,使用函数参数比使用高度范围的变量要好得多。范围是避免冲突的一种方式,而不是障碍。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-01
      • 2016-11-22
      • 2014-09-14
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 2011-11-24
      • 1970-01-01
      相关资源
      最近更新 更多