为什么我不能在Integer类中覆盖self?

时间:2015-01-22 07:51:04

标签: ruby class metaprogramming

我希望能够写出number.incr,如下所示:

num = 1; num.incr; num #=> 2

我看到的错误是: Can't change the value of self

如果那是真的,怎么轰!方法有效吗?

2 个答案:

答案 0 :(得分:3)

您无法更改self

的值

一个对象是class pointer and a set of instance methods(请注意,这个链接是Ruby的旧版本,因为它非常简单,因此更好地用于解释目的)。

对象的“指向”意味着您有一个变量,用于将对象的位置存储在内存中。然后要对对象做任何事情,首先要转到内存中的位置(我们可能会说“跟随指针”)来获取对象,然后执行操作(例如调用方法,设置ivar)。

所有Ruby代码都在某个对象的上下文中执行。这是保存实例变量的地方,这是Ruby查找没有接收器的方法(例如$stdout$stdout.puts "hi"中的接收器,当前对象是{{1}中的接收器}})。有时您需要对当前对象执行某些操作。处理对象的方法是通过变量,但是哪个变量指向当前对象?没有一个。为了满足这一需求,我们提供了关键字puts "hi"

self就像一个变量,因为它指向当前对象的位置。但它不像变量,因为你不能为它赋予新的价值。如果可以的话,那个点之后的代码会突然在另一个对象上运行,这会让人感到困惑,并且没有使用变量的好处。

还要记住,对象由存储内存地址的变量跟踪。什么是self应该是什么意思?它是否仅表示当前代码的操作就像调用self = 2一样?或者它是否意味着指向旧对象的所有变量现在都将其值更新为指向新值?这不是很清楚,但前者不必要地引入了身份危机,而后者非常昂贵,并且引入了不清楚什么是正确的情况(我将在下面进一步讨论)。

你不能改变Fixnums

Some objects在Ruby中的C级别是特殊的(false,true,nil,fixnums和symbols)。

指向它们的变量实际上并不存储内存位置。相反,地址本身存储对象的类型和标识。无论在何处重要,Ruby都会检查它是否是一个特殊对象(例如,当looking up an instance variable时),然后从中提取值。

因此内存中没有存储对象2的位置。这意味着123包含Fixnum self的想法,而不是像往常一样的内存地址。与变量一样,它将在必要时进行检查和处理。

因此,你不能改变对象本身(虽然看起来它们保持a special global variable以允许你在像Symbols这样的东西上设置实例变量。)

他们为什么要这样做呢?为了提高性能,我假设。存储在寄存器中的数字只是一系列位(通常为32或64位),这意味着存在加法和乘法之类的硬件指令。也就是说,ALU被连线以在单个时钟周期内执行这些操作,而不是用软件编写算法,这将花费更多的数量级。通过像这样存储它们,它们避免了在内存中存储和查看对象的成本,并且它们获得了可以使用硬件直接添加两个指针的优点。但是请注意,Ruby中还有一些额外的成本(C中没有)(例如检查溢出并将结果转换为Bignum)。

Bang方法

你可以在任何方法结束时发出爆炸声。它不需要改变对象,只是当你做一些可能产生意想不到的副作用的事情时,人们通常会试着警告你。

123

此外,整数上没有爆炸方法,它不适合范式

class C
  def initialize(val)
    @val = val         # => 12
  end                  # => :initialize

  def bang_method!
    "My val is: #{@val}"  # => "My val is: 12"
  end                     # => :bang_method!
end                       # => :bang_method!

c = C.new 12    # => #<C:0x007fdac48a7428 @val=12>
c.bang_method!  # => "My val is: 12"
c               # => #<C:0x007fdac48a7428 @val=12>

替代

  • 制作一个包装对象:我不打算提倡这个,但它最接近你想做的事情。基本上创建自己的类,它是可变的,然后使它看起来像一个整数。有一篇很棒的博客文章在http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html处走过,它会让你95%的路上
  • 不要直接依赖于Fixnum的价值:如果不知道你想要做什么/为什么你认为这是一个需要,我不能给出更好的建议。

此外,当您提出这样的问题时,您应该显示您的代码。我误解了你是如何接近它的。

答案 1 :(得分:2)

根本无法将self更改为其他对象。 self是邮件发送的接收者。只能有一个。

  

如果这是真的,怎么会爆炸!方法有效吗?

爆炸(!)只是方法名称的一部分。它绝对没有任何特殊意义。 Ruby程序员之间的惯例是用一声巨响命名令人惊讶的不太令人惊讶的方法变体,但这只是一个惯例。