在它自己的方法中替换对象的通用方法

时间:2012-02-03 15:19:46

标签: ruby

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

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

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

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

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

我知道可以在String上使用一些技巧,但是如果我尝试为Object执行类似的操作呢?

4 个答案:

答案 0 :(得分:7)

许多类都是不可变的(例如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

答案 1 :(得分:4)

嗯,upcase!方法不会更改对象标识,只会更改其内部结构(s.object_id == s.upcase!.object_id)。

另一方面,数字是不可变对象,因此,您无法在不更改其身份的情况下更改其值。 AFAIK,对象无法自我更改其身份,但是,当然,您可以实现更改其对象属性的positify!方法 - 而将类似于怎么了!为字符串做。

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

您不能将self更改为指向除当前对象之外的任何内容。您可以更改实例变量,例如在将基础字符更改为大写字母的大小写字符串中。

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

这里提到的一个技巧是解决方法,即将您的类编写为另一个对象的包装器。然后你的包装类可以随意替换包装对象。我犹豫是否说这是一个好主意。