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


130

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

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并进行设置,为什么不这样做++呢?

包含=字符的作业的一致性是唯一的原因,还是我缺少某些东西?


2
Grep ruby​​此类运算符的源代码。如果没有-Matz不喜欢他们。
Eimantas

您无法通过+=运算符进行预增量。在CI中,尝试在条件语句中仅使用++/ --,而在基本语句中优先使用更文字的+=/ -=。可能是因为我学过Python(尽管在C之后很久……)
Nick T

就在昨天,Python是否没有这样的问题?
BoltClock

@Eimantas很明显,该语言的创建者不喜欢他们。这太普遍了,不能忽视。我想知道为什么,下面的答案对此有所澄清。
Andy_Vulhop 2010年

1
我认为这(几乎)是一个模型问题。要获得经过考虑的答复,并非易事。要求什么答案是非常明确和具体的,并且答案阐明了编程的一个方面,这一方面可以使人们思考的范围不仅仅是问题的核心。
PurplePilot 2010年

Answers:


97

这是Matz(Yukihiro Matsumoto)在旧线程中的解释方式:

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.

10
2和3似乎是矛盾的。如果自我分配不好,为什么+=/ -=还可以?而且不会那么1+=1糟糕吗?(它在带有IRB的IRB中失败syntax error, unexpected ASSIGNMENT
Andy_Vulhop 2010年

2
(2)表示在C语言中,您并没有更改值本身,而是在更改保存该值的变量的内容。对于按值传递的任何语言来说,这有点太元了。除非有一种方法可以在Ruby中通过引用传递某些内容(并且我的意思是真正的“通过引用”,而不是通过值传递引用),否则在方法中无法更改变量本身。
cHao 2010年

5
也许我在这里错过了一些东西。+=将变量引用的对象替换为一个全新的对象。您可以i.object_id在之前和之后致电进行检查i+=1。为什么在技术上会更棘手++
Andy_Vulhop,2010年

6
@Andy_Vulhop:#3解释了为什么从技术上讲分配是一种方法是不可能的,而不是为什么分配通常是不可能的(发贴人Matz回答说可能创建一个++方法)。
Chuck

2
在Ruby中,所有文字也是对象。因此,我相信Matz试图说出自己不确定他是否喜欢将1 ++作为声明的想法。我个人认为这是不合理的,因为@Andy_Vulhop说1 + = 2一样古怪,而Ruby在执行此操作时只会引发错误。因此1 ++并不难处理。解析器可能需要处理这种语法糖,这是不可取的。
史蒂夫·米德利

28

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

另一个原因是,行为++--经常混淆的人。i++举例:您的示例中的返回值实际上是1,而不是2(但是,新值i是2)。


4
到目前为止,比所有其他原因更为重要的是,“所有作业中都有一个”的合理性=似乎很有意义。我可以严格遵守一致性,以此来表示敬意。
Andy_Vulhop 2010年

那呢:a。资本化!(隐式分配a)
路易斯·苏亚雷斯

1
@LuísSoares a.capitalize!不会重新分配a,它会使a引用的字符串发生突变。对同一字符串的其他引用也会受到影响,如果a.object_id在调用之前和之后执行capitalize,您将得到相同的结果(如果a = a.capitalize相反,则两者都不是正确的)。
sepp2k 2016年

1
如我所说,@LuísSoares a.capitalize!将影响对同一字符串的其他引用。这是非常实际的差异。例如,如果您拥有def yell_at(name) name.capitalize!; puts "HEY, #{name}!" end,然后按如下方式调用它:my_name = "luis"; yell_at(my_name)my_name则现在的值将为"LUIS",而如果您使用capitalize和赋值,它将不受影响。
sepp2k 2016年

1
哇。太可怕了...知道Java字符串是不可变的。.但是,伴随着力量而来的是责任。感谢您的解释。
路易斯·苏亚雷斯

25

在OO语言中这不是常规的。实际上,++在Smalltalk中,没有一种语言造就了“面向对象程序设计”一词(而Ruby语言受其影响最大)。您的意思是说,它是C语言中的常规语言,并且语言在很大程度上模仿C语言。Ruby确实具有某种类似于C的语法,但在遵循C语言传统方面并不奴役。

至于为什么它不在Ruby中:Matz不想要它。这确实是最终原因。

在Smalltalk中不存在这种情况的原因是,这是该语言最重要的思想的一部分,即,从根本上说,分配变量与向对象发送消息相比,它是另一种事物-处于不同的层次。这种想法可能影响了Matz设计Ruby。

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


1
我认为您的预处理器建议无效。(不是专家),但我认为i = 42,i ++将返回42,而i + = 1将返回43。因此,在这种情况下,您的建议是使用i ++,因为通常使用++ i,这是非常糟糕的恕我直言,并且可能造成弊大于利。
AturSams 2014年

12

我认为还有另一个原因:++在Ruby中,像在C及其直接后继版本中那样,远程有用性并不高。

原因是for关键字:尽管它在C语言中必不可少,但在Ruby中几乎是多余的。大多数在Ruby中的迭代是通过可枚举的方法,如做eachmap何时迭代通过一些数据结构,和Fixnum#times方法,当你需要循环的次数一个确切的数字。

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

简而言之,是否真的使用方法++和真的值得怀疑--


1
这是恕我直言的最佳答案。++通常用于迭代。Ruby不鼓励这种类型的迭代。
AturSams 2014年

3

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

例如:

一个= SomeClass.new
def a.go
  '你好'
结束
#此时,您可以致电a.go
#但如果您做了a ++
#确实意味着a = a + 1
#,因此您无法再致电a.go
#由于您丢失了原件

现在,如果有人可以说服他,那就应该打电话给#succ!或什么都不是,那会更有意义,并避免出现问题。您可以在ruby core上建议它。


9
“你可以认为它红宝石核心” ...... 之后您已经阅读在此之前,在所有地方有人提出最后一次其他线程了解的参数,而在这之前的时间,而在这之前的时间,时间,以及之前的时间,以及……我没去过Ruby社区很长时间,但是就在我这段时间里,我记得至少有20场这样的讨论。
约尔格W¯¯米塔格

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

有关“类变量”的更多信息,请参见“ 类变量以增加Fixnum对象 ”。


2

用戴维·布莱克(David Black)在他的《全熟的红宝石主义者》中的话说:

Ruby中的某些对象作为立即值存储在变量中。其中包括整数,符号(看起来像:this)以及特殊对象true,false和nil。当将这些值之一分配给变量(x = 1)时,变量将保留值本身,而不是对其的引用。实际上,这无关紧要(在本书的参考文献和相关主题的讨论中,通常会隐含而不是反复说明)。Ruby自动处理对象引用的取消引用。与包含立即数整数的对象相反,您无需执行任何额外的工作即可将消息发送到包含例如对字符串的引用的对象。但是立即值表示法规则有一些有趣的后果,尤其是整数。一方面,任何代表为立即数的对象始终完全相同,无论分配了多少变量。只有一个对象100,只有一个对象false,依此类推。整数绑定变量的直接,独特的性质是Ruby缺少前后递增运算符的原因-也就是说,您不能在Ruby中执行此操作:x = 1 x ++#没有这样的运算符原因是由于在x中立即存在1的情况下,x ++就像1 ++,这意味着您要将数字1更改为数字2,这毫无意义。无论分配了多少个变量。只有一个对象100,只有一个对象false,依此类推。整数绑定变量的直接,独特的性质是Ruby缺少前后递增运算符的原因-也就是说,您不能在Ruby中执行此操作:x = 1 x ++#没有这样的运算符原因是由于在x中立即存在1的情况下,x ++就像1 ++,这意味着您要将数字1更改为数字2,这毫无意义。无论分配了多少个变量。只有一个对象100,只有一个对象false,依此类推。整数绑定变量的直接,独特的性质是Ruby缺少前后递增运算符的原因-也就是说,您不能在Ruby中执行此操作:x = 1 x ++#没有这样的运算符原因是由于在x中立即存在1的情况下,x ++就像1 ++,这意味着您要将数字1更改为数字2,这毫无意义。


但是,您怎么才能执行“ 1.next”呢?
Magne

1

通过在fixnum或Integer类中添加新方法无法实现?

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

返回2

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

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

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

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


1
Integer#next已经存在(或多或少),除了被调用Integer#succ(对于“后继”)。但是Integer#next!(或Integer#succ!)会胡说八道:请记住,方法只对对象起作用,而不对变量起作用,因此numb.next!将完全等于1.next!,也就是说,它将1突变为等于2++可能会更好,因为它可能是分配的语法糖,但就我个人而言,我更喜欢当前语法,其中所有分配均使用完成=
philomory '16

完成以上评论:并Integer#pred检索前任。
Yoni,

-6

从Ruby的irb的C系列中检查这些运算符,并自己进行测试:

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

3
显然这是错误的,并且不起作用,就像(x++)Ruby中的无效语句一样。
anothermh
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.