Ruby 为什么可以';我不能在Integer类中覆盖self吗?
我想能够写Ruby 为什么可以';我不能在Integer类中覆盖self吗?,ruby,class,metaprogramming,Ruby,Class,Metaprogramming,我想能够写number.incr,就像这样: num=1;数量增加;号码 #=>2 我看到的错误是: 无法更改self的值 如果那是真的,那你怎么办!方法有效吗?根本不可能将自己改变成另一个对象self是发送消息的接收者。只能有一个 如果那是真的,那你怎么办!方法有效吗 bang(!)只是方法名称的一部分。绝对没有什么特别的意义。Ruby程序员习惯于用“砰”的一声命名不那么令人惊讶的方法的令人惊讶的变体,但这只是一种习惯。根本不可能将self更改为另一个对象self是发送消息的接收者。只能有一个
number.incr
,就像这样:
num=1;数量增加;号码
#=>2
我看到的错误是:
无法更改self的值
如果那是真的,那你怎么办!方法有效吗?根本不可能将自己改变成另一个对象
self
是发送消息的接收者。只能有一个
如果那是真的,那你怎么办!方法有效吗
bang(
!
)只是方法名称的一部分。绝对没有什么特别的意义。Ruby程序员习惯于用“砰”的一声命名不那么令人惊讶的方法的令人惊讶的变体,但这只是一种习惯。根本不可能将self
更改为另一个对象self
是发送消息的接收者。只能有一个
如果那是真的,那你怎么办!方法有效吗
bang(!
)只是方法名称的一部分。绝对没有什么特别的意义。Ruby程序员习惯于用“砰”的一声命名不那么令人惊讶的方法的令人惊讶的变体,但那只是一种习惯。你不能改变self的值
对象是一个(请注意,此链接是Ruby的旧版本,因为它非常简单,因此更好地用于解释目的)
“指向”一个对象意味着你有一个变量,它将对象的位置存储在内存中。然后,要对该对象执行任何操作,您首先要转到内存中的位置(我们可以说“跟随指针”)获取该对象,然后执行该操作(例如,调用一个方法,设置一个ivar)
所有Ruby代码都在某个对象的上下文中执行。这是保存实例变量的地方,也是Ruby查找没有接收器的方法的地方(例如,$stdout
是$stdout.puts“hi”
中的接收器,当前对象是puts“hi”
中的接收器)。有时需要对当前对象执行某些操作。使用对象的方法是通过变量,但哪些变量指向当前对象?没有。为了满足这一需求,提供了关键字self
self
的作用类似于一个变量,因为它指向当前对象的位置。但它不像一个变量,因为你不能给它赋值。如果可以的话,在这一点之后的代码会突然在另一个对象上运行,这会让人感到困惑,并且与仅仅使用变量相比没有任何好处
还要记住,对象是由存储内存地址的变量跟踪的。self=2
应该是什么意思?这是否仅仅意味着当前代码的操作就好像它是被调用的2
?或者这意味着所有指向旧对象的变量的值现在都更新为指向新对象?这并不十分清楚,但前者不必要地引入了身份危机,而后者的成本高得让人望而却步,并且引入了不清楚什么是正确的情况(我将在下面进一步讨论)
你不能变异Fixnums
在Ruby中的C级别是特殊的(false、true、nil、fixnums和Symbol)
指向它们的变量实际上并不存储内存位置。相反,地址本身存储对象的类型和标识。无论在什么地方,Ruby都会检查它是否是一个特殊的对象(例如何时),然后从中提取值
因此,内存中没有存储对象123
的位置。这意味着self
包含了Fixnum123
的概念,而不是像通常那样的内存地址。与变量一样,它将在必要时进行检查和特殊处理
因此,您无法改变对象本身(尽管它们似乎保持不变,以允许您在符号等对象上设置实例变量)
他们为什么要这么做?为了提高性能,我假设。存储在寄存器中的数字只是一系列位(通常为32或64位),这意味着存在用于加法和乘法之类的硬件指令。也就是说,ALU被连接在一个时钟周期内执行这些操作,而不是用软件编写算法,这将花费许多数量级的时间。通过这样存储它们,它们避免了在内存中存储和查找对象的成本,并且获得了可以使用硬件直接添加两个指针的优势。然而,请注意,Ruby中仍然存在一些C中没有的额外成本(例如,检查溢出并将结果转换为Bignum)
爆炸法
你可以在任何方法的末尾加上一记重击。它不需要改变对象,只是当你做一些可能产生意外副作用的事情时,人们通常会试图警告你
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>
选择
- 制作一个包装器对象:我不打算提倡这个,但它最接近您要做的。基本上创建您自己的类,它是可变的,然后使它看起来像一个整数。这里有一篇很棒的博客文章,在这里浏览一下,你会有95%的收获
- 不要直接依赖于Fixnum的价值:如果不知道你想做什么/为什么你觉得这是一种需要,我就不能给出比这更好的建议
另外,当你问这样的问题时,你应该展示你的代码。很长一段时间以来,我误解了你是如何接近它的。你不能改变自我的价值观 对象是一个(请注意,此链接是Ruby的旧版本,因为它非常简单,因此更好地用于解释目的) “指向”一个对象意味着你有一个变量,它将对象的位置存储在内存中。然后,要对对象执行任何操作,首先要转到内存中的位置(我们可以说“跟随指针”),以获取
Fixnum.instance_methods.grep(/!$/) # => [:!]
# Okay, there's one, but it's actually a boolean negation
1.! # => false
# And it's not a Fixnum method, it's an inherited boolean operator
1.method(:!).owner # => BasicObject
# In really, you call it this way, the interpreter translates it
!1 # => false