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

时间:2010-09-07 16:25:21

标签: ruby operators language-design

前/后递增/递减运算符(++--)是非常标准的编程语言语法(至少对于过程语言和面向对象语言)。

为什么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并设置它,为什么不对++执行相同操作?

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

10 个答案:

答案 0 :(得分:88)

以下是Matz(Yukihiro Matsumoto)在旧版thread中解释它的方法:

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.

答案 1 :(得分:28)

一个原因是到目前为止,每个赋值运算符(即更改变量的运算符)中都有=。如果您添加++--,则不再是这种情况。

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

答案 2 :(得分:23)

在OO语言中并不常见。事实上,Smalltalk中没有++,这种语言创造了“面向对象编程”这一术语(而Ruby语言受其影响最大)。你的意思是它在 C 中是常规的,并且语言非常模仿C. Ruby确实有一种类似C语言的语法,但它并不是坚持C语言的传统。

至于为什么它不在Ruby中:Matz不想要它。这才是真正的终极原因。

Smalltalk中不存在这样的事情的原因是因为它是语言最重要的哲学的一部分,分配变量基本上是一种不同于向对象发送消息的种类 - 它是在不同的水平。这种想法可能影响了Matz设计Ruby。

将它包含在Ruby中并不是不可能的 - 您可以轻松编写一个将所有++转换为+=1的预处理器。但显然Matz并不喜欢操作员做过“隐藏任务”的想法。拥有一个隐藏整数操作数的运算符也似乎有点奇怪。该语言中没有其他操作员以这种方式工作。

答案 3 :(得分:10)

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

原因是for关键字:虽然它在C中是必不可少的,但它在Ruby中基本上是多余的。 Ruby中的大部分迭代都是通过Enumerable方法完成的,例如eachmap在迭代某些数据结构时,以及Fixnum#times方法,当你需要循环一个确切的次数时。

实际上,就我所见,大部分时间+=1被新人从C风格语言迁移到Ruby使用。

简而言之,如果完全使用方法++--,那确实值得怀疑。

答案 4 :(得分:3)

我认为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

现在,如果有人能说服他,那就应该叫#succ!或者什么不是,这会更有意义,并避免问题。你可以在红宝石核心上建议它。

答案 5 :(得分:3)

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

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

Class Variable to increment Fixnum objects”中提供了有关“类变量”的更多信息。

答案 6 :(得分:2)

And in the words of David Black from his book "The Well-Grounded Rubyist":

Some objects in Ruby are stored in variables as immediate values. These include integers, symbols (which look like :this), and the special objects true, false, and nil. When you assign one of these values to a variable (x = 1), the variable holds the value itself, rather than a reference to it. In practical terms, this doesn’t matter (and it will often be left as implied, rather than spelled out repeatedly, in discussions of references and related topics in this book). Ruby handles the dereferencing of object references automatically; you don’t have to do any extra work to send a message to an object that contains, say, a reference to a string, as opposed to an object that contains an immediate integer value. But the immediate-value representation rule has a couple of interesting ramifications, especially when it comes to integers. For one thing, any object that’s represented as an immediate value is always exactly the same object, no matter how many variables it’s assigned to. There’s only one object 100, only one object false, and so on. The immediate, unique nature of integer-bound variables is behind Ruby’s lack of pre- and post-increment operators—which is to say, you can’t do this in Ruby: x = 1 x++ # No such operator The reason is that due to the immediate presence of 1 in x, x++ would be like 1++, which means you’d be changing the number 1 to the number 2—and that makes no sense.

答案 7 :(得分:2)

Ruby 中的某些对象作为立即值存储在变量中。其中包括整数、符号(类似于 :this)以及特殊对象 true、false 和 nil。当您将这些值之一分配给变量 (x = 1) 时,该变量将保存该值本身,而不是对它的引用。

任何表示为立即数的对象始终是完全相同的对象,无论它分配给多少个变量。只有一个对象 100,只有一个对象是 false,依此类推。

整数绑定变量的直接、独特的性质是 Ruby 缺乏前置和后置递增运算符的原因——也就是说,你不能在 Ruby 中做到这一点:

<块引用>

x=1

x++ # 没有这样的操作符

原因是,由于 x 中直接存在 1,x++ 将类似于 1++,这意味着您会将数字 1 更改为数字 2——这没有任何意义。< /strong>

答案 8 :(得分:1)

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

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

返回2

“破坏性”方法似乎附加了!来警告可能的用户,因此添加一个名为next!的新方法几乎可以满足要求,即。

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

返回2(因为麻木已经增加)

当然,next!方法必须检查对象是整数变量而不是实数,但可用。

答案 9 :(得分:-6)

使用Ruby的irb中的C系列检查这些运算符并自行测试:

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