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

使用字符串可以执行此操作:

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

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

像(虽然这显然不起作用):

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

我知道可以在String上使用一些技巧,但是如果我想为Object做这样的事情呢?

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

另一方面,数字是不可变对象,因此,在不改变其身份的情况下,您无法更改其值。 AFAIK,对象无法自行更改其身份,但是,当然,您可以实现positify! 改变其对象属性的方法 – 将是一个夸张的类比! 为字符串做。

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

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

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

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

正如在这个答案中指出的: Ruby和为Float实例修改self

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