为什么 Ruby 不支持 i + + 或 i ——(递增/递减运算符) ?

前/后递增/递减操作符(++--)是相当标准的编程语言语法(至少对于过程语言和面向对象语言)。

为什么 Ruby 不支持他们?我理解您可以用 +=-=完成同样的事情,但是排除这样的东西似乎有点任意,特别是因为它是如此简洁和传统。

例如:

i = 0    #=> 0
i += 1   #=> 1
i        #=> 1
i++      #=> expect 2, but as far as I can tell,
#=> irb ignores the second + and waits for a second number to add to i

我知道 Fixnum是不可变的,但是如果 +=可以实例化一个新的 Fixnum并设置它,为什么不对 ++做同样的事情呢?

包含 =字符的作业的一致性是导致这种情况的唯一原因吗,还是我遗漏了什么?

41824 次浏览

其中一个原因是,到目前为止,每个赋值操作符(例如,更改变量的操作符)都有一个 =。如果加上 ++--,情况就不再是这样了。

另一个原因是 ++--的行为经常使人感到困惑。例如: 在您的示例中,i++的返回值实际上是1,而不是2(但是,i的新值将是2)。

以下是马茨(松本行弘)在一个旧的 线中的解释:

Hi,


In message "[ruby-talk:02706] X++?"
on 00/05/10, Aleksi Niemelä <aleksi.niemela@cinnober.com> writes:


|I got an idea from http://www.pragprog.com:8080/rubyfaq/rubyfaq-5.html#ss5.3
|and thought to try. I didn't manage to make "auto(in|de)crement" working so
|could somebody help here? Does this contain some errors or is the idea
|wrong?


(1) ++ and -- are NOT reserved operator in Ruby.


(2) C's increment/decrement operators are in fact hidden assignment.
They affect variables, not objects.  You cannot accomplish
assignment via method.  Ruby uses +=/-= operator instead.


(3) self cannot be a target of assignment.  In addition, altering
the value of integer 1 might cause severe confusion throughout
the program.


matz.

我认为 Matz 不喜欢它们的原因是它实际上用一个新的变量替换了变量。

例如:

a = SomeClass.new
def a.go
'hello'
end
# at this point, you can call a.go
# but if you did an a++
# that really means a = a + 1
# so you can no longer call a.go
# as you have lost your original

现在,如果有人能说服他,它应该只是叫 # 成功!或者不是什么,这样会更有意义,并避免问题。你可以建议用红宝石芯片。

它在 OO 语言中不是常规的。事实上,在 Smalltalk 中没有 ++,这种语言创造了“面向对象程序设计”这个词(而 Ruby 受其影响最大)。你的意思是,它在 C中是常规的,语言非常模仿 C。 Ruby 的语法确实有点像 C 语言,但是它并没有盲从于 C 语言的传统。

至于为什么 Ruby 中没有: Matz 不想要它,这就是最终的原因。

Smalltalk 之所以没有这样的东西,是因为赋予变量与向对象发送消息从根本上来说是不同的 善良,这是该语言最重要的哲学思想的一部分ーー这是在一个不同的层次上。这种想法可能影响了 Matz 在设计 Ruby 的过程中。

在 Ruby 中包含它并非不可能ーー你可以很容易地编写一个将所有 ++转换成 +=1的预处理器。但显然,马茨不喜欢运算符执行“隐藏赋值”的想法有一个运算符内部有一个隐藏的整数操作数,这看起来也有点奇怪。语言中没有其他操作符是这样工作的。

我认为还有另外一个原因: Ruby 中的 ++远不如 C 及其直接后继者有用。

原因是,for关键字: 虽然它在 C 语言中是必不可少的,但在 Ruby 中却是多余的。Ruby 中的大多数迭代都是通过 Enumable 方法完成的,例如在遍历某些数据结构时使用 eachmap,在需要循环一定次数时使用 Fixnum#times方法。

实际上,据我所知,大多数时候 +=1都是刚从 C 风格语言迁移到 Ruby 的人使用的。

简而言之,是否会使用 ++--方法确实值得怀疑。

您可以定义一个 .+自增运算符:

class Variable
def initialize value = nil
@value = value
end
attr_accessor :value
def method_missing *args, &blk
@value.send(*args, &blk)
end
def to_s
@value.to_s
end


# pre-increment ".+" when x not present
def +(x = nil)
x ? @value + x : @value += 1
end
def -(x = nil)
x ? @value - x : @value -= 1
end
end


i = Variable.new 5
puts i                #=> 5


# normal use of +
puts i + 4            #=> 9
puts i                #=> 5


# incrementing
puts i.+              #=> 6
puts i                #=> 6

有关「类别变数」的详细资料,请参阅「 类变量以递增 Fixnum 对象」。

这难道不能通过向 fixnum 或 Integer 类添加一个新方法来实现吗?

$ ruby -e 'numb=1;puts numb.next'

报税表2

“破坏性”的方法似乎附加了 !来警告可能的用户,所以添加一个新的方法称为 next!将几乎完成所要求的即。

$ ruby -e 'numb=1; numb.next!; puts numb'

返回2(因为数据已经递增)

当然,next!方法必须检查对象是否是一个整数变量,而不是一个实数,但是这个 应该是可用的。

检查 Ruby 的 irb 中 C 家族的这些操作符,然后自己测试它们:

x = 2    # x is 2
x += 2   # x is 4
x++      # x is now 8
++x      # x reverse to 4

用大卫 · 布莱克(David Black)在其著作《扎实的红宝石爱好者》(The Well-GroundedRubyist)中的话说:

Ruby 中的一些对象作为直接值存储在变量中 整数、符号(看起来像: this)和特殊对象 true、 false 和 当您将这些值中的一个赋给一个变量(x = 1)时,该变量保持 值本身,而不是对它的引用。 实际上,这并不重要(而且它往往被视为暗示,而不是 在本书的参考文献和相关主题的讨论中反复阐述)。 Ruby 会自动处理对象引用的解引用; 您不必这样做 执行任何额外的工作,将消息发送到包含(比如) 一个字符串,与包含直接整数值的对象相反。 但是直接价值表示法则有几个有趣的分支, 特别是当涉及到整数的时候。首先,任何表示 作为一个直接值,总是完全相同的对象,无论多少 只有一个对象100只有一个对象 false 等等。 The immediate, unique nature of integer-bound variables is behind Ruby’s lack of 前增量和后增量运算符ーー也就是说,在 Ruby 中不能这样做: X = 1 X + + # 没有这样的运算符 原因是由于 x 中立即存在1 x + + 等于1 + + , 也就是说你把数字1改成了数字2 没道理。

Ruby 中的一些对象作为直接值存储在变量中。其中包括 整数、符号(看起来像: this)和特殊对象 true、 false 和 nil。当您将其中一个值赋给一个变量(x = 1)时,该变量保存的是该值本身,而不是对它的引用。

任何表示为直接值的对象总是完全相同的对象,无论它被赋予多少变量。只有一个对象100,只有一个对象 false,以此类推。

整数绑定变量的直接、独特性质是 Ruby 缺少前后递增运算符的原因ーー也就是说,在 Ruby 中无法做到这一点:

X = 1

X + + # 没有这样的运算符

原因是由于 x 中立即存在1 x + + 就像1 + + 这意味着你要把数字1改成数字2这毫无意义。