【问题标题】:Generic way to replace an object in it's own method用自己的方法替换对象的通用方法
【发布时间】:2012-02-03 15:19:45
【问题描述】:

使用字符串可以做到这一点:

a = "hello"
a.upcase!
p a #=> "HELLO"

但是我该如何编写自己的方法呢?

类似的东西(虽然这显然不起作用):

class MyClass
  def positify!
    self = [0, self].max
  end
end

我知道可以在 String 上使用一些技巧,但是如果我想为 Object 做类似的事情怎么办?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    许多类是不可变的(例如NumericSymbol、...),因此没有方法允许您更改它们的值。

    另一方面,任何Object 都可以有实例变量并且可以修改这些变量。

    有一种简单的方法可以将行为委托给已知对象(比如42),然后可以使用SimpleDelegator 将其更改为另一个对象。在下面的示例中,quacks_like_an_int 的行为类似于 Integer

    require 'delegate'
    quacks_like_an_int = SimpleDelegator.new(42)
    quacks_like_an_int.round(-1) # => 40
    quacks_like_an_int.__setobj__(666)
    quacks_like_an_int.round(-1) # => 670
    

    你也可以用它来设计一个类,例如:

    require 'delegate'
    class MutableInteger < SimpleDelegator
      def plus_plus!
        __setobj__(self + 1)
        self
      end
    
      def positify!
        __setobj__(0) if self < 0
        self
      end
    end
    
    i = MutableInteger.new(-42)
    i.plus_plus! # => -41
    i.positify! # => 0
    

    【讨论】:

      【解决方案2】:

      嗯,upcase! 方法不会改变对象身份,它只会改变其内部结构 (s.object_id == s.upcase!.object_id)。

      另一方面,数字是不可变的对象,因此,如果不改变它们的标识,就不能改变它们的值。 AFAIK,对象无法自行更改其身份,但是,当然,您可以实现 positify! 更改其对象属性的方法 - 而 this 将类似于大写!用于字符串。

      【讨论】:

        【解决方案3】:

        局部变量的赋值或绑定(使用= 运算符)是核心语言内置的,无法覆盖或自定义它。不过,您可以在您的 Ruby 代码上运行一个预处理器,它将您自己的自定义语法转换为有效的 Ruby。您还可以将Binding 传递给自定义方法,该方法可以动态重新定义变量。但是,这不会达到您想要的效果。

        了解self = 永远不会起作用,因为当您说a = "string"; a = "another string" 时,您并没有修改任何对象;您正在将局部变量重新绑定到不同的对象。在您的自定义方法中,您处于不同的范围内,您绑定的任何局部变量都将仅存在 该范围内;它不会对您调用该方法的范围产生任何影响。

        【讨论】:

          【解决方案4】:

          您不能将 self 更改为指向当前对象以外的任何内容。您可以更改实例变量,例如将底层字符更改为大写的 case 字符串。

          正如这个答案所指出的: Ruby and modifying self for a Float instance

          这里提到的一个技巧是一种变通方法,即将你的类编写为另一个对象的包装器。然后你的包装类可以随意替换被包装的对象。不过,我不敢说这是个好主意。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-12
            • 2021-12-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多