2010-09-07 53 views
116

前/后增加/减少运算符(++--)是非常标准的编程语言语法(至少对于过程和面向对象的语言)。为什么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并设置它,为什么不为++做?

是否包含=字符的赋值一致性是唯一原因,还是我错过了什么?

+2

Grep这样的操作符的源代码。如果没有 - 马茨不喜欢他们。 – Eimantas 2010-09-07 16:29:50

+0

你不能用'+ ='操作符来预先增加。在C中,我尝试仅在条件语句中使用'++'/'--',在基本语句中宁愿使用更多的'+ ='/' - ='。可能是因为我学习了Python(在C之后很长,但是...) – 2010-09-07 16:35:25

+0

昨天Python没有像这样的问题吗? – BoltClock 2010-09-07 16:41:26

回答

82

这里是马茨(松本行弘)如何解释它在一个古老的thread

Hi, 

In message "[ruby-talk:02706] X++?" 
    on 00/05/10, Aleksi Niemelä <[email protected]> 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. 
+8

2和3似乎矛盾。如果自我分配不好,为什么'+ ='/' - ='好吗?并不会'1 + = 1'一样糟糕吗? (它在IRB语法错误,意外的ASSIGNMENT中失败) – 2010-09-07 16:44:17

+2

(2)意味着在C中,你并没有改变这个值本身......你改变了保存该值的变量的内容。对于任何通过价值传递的语言来说,这都太过分了。除非有一种方法可以在Ruby中通过引用传递某些东西(我的意思是真正的“通过引用”,而不是通过值传递引用),但是在方法中更改变量本身是不可能的。 – cHao 2010-09-07 16:57:23

+4

也许我在这里错过了一些东西。 '+ ='用一个全新的对象替换对象的变量引用。你可以通过在'i + = 1'前后调用'i.object_id'来检查。为什么用'++'做技术上更棘手? – 2010-09-07 17:09:21

27

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

另一个原因是++--的行为经常让人迷惑。例子:在你的例子中i++的返回值实际上是1,而不是2(然而,新值i将是2)。

+4

迄今为止,除了任何其他原因之外,“所有作业都有'='在其中”的理性似乎是有道理的。我可以尊重这一点,即坚持一致性。 – 2010-09-07 16:45:56

+0

这个怎么样: a.capitalize! (隐式赋值a) – 2016-07-06 22:31:03

+1

@LuísSoares'a.capitalize!'不会重新赋值'a',它会改变'a'引用的字符串。对相同字符串的其他引用将受到影响,如果在调用'capitalize'前后执行'a.object_id',则会得到相同的结果(如果执行了'a = a,则两者都不会是真的。大写)代替)。 – sepp2k 2016-07-06 22:46:48

3

我觉得麦茨的推理不喜欢他们的是,它其实是将一个新的变量。

例如:

 
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!或者什么不是,那会更有意义,并且避免这个问题。你可以在ruby core上建议它。

+9

“你可以在ruby core上建议它”...... *在*之后,你已经阅读了*和*了解上次建议的所有其他线程中的参数,以及之前的时间以及之前的时间,以及在那之前的那段时间,以及之前的那段时间,......我没有在Ruby社区很长时间,但是在我的时间里,我记得至少有二十次这样的讨论。 – 2010-09-07 17:01:24

23

这在OO语言中不是常规的。实际上,Smalltalk中没有++,这是创造了“面向对象编程”这个术语的语言(以及Ruby最受其影响的语言)。你的意思是,这是传统的C和语言密切模仿C. Ruby有一个类似C语法的语法,但它不坚持C传统奴役。

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

Smalltalk中没有这种事情存在的原因是因为它是语言压倒一切的理念的一部分,赋予一个变量从根本上说是一种不同的东西,而不是向对象发送消息 - 它是在不同的级别上。这种想法可能影响了Matz在设计Ruby时的感受。

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

+1

我不认为你的预处理器的建议会工作; (不是专家),但我认为i = 42,i ++将返回42,其中i + = 1将返回43。所以你在这种情况下的建议是使用i ++作为++我通常使用这是非常糟糕的恕我直言,可以造成更多的伤害,而不是好的。 – zehelvion 2014-07-23 07:37:16

8

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

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

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

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

+1

这是最佳答案imho。 ++通常用于迭代。 Ruby不鼓励这种类型的迭代。 – zehelvion 2014-07-23 07:39:40

2

您可以定义一个.+自增运算符:在“类变量”

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”可用。

1

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

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

回报2

“破坏性”的方法似乎与!附加警告可能的用户,所以加入了一个名为next!将几乎做的是什么要求,即新方法。

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

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

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

+1

'整数#下一个'已经存在(或多或少),除了它被称为'整数#succ'代替(对于'后继')。但是'Integer#next!'(或'Integer#succ!')将是无稽之谈:请记住,方法对_objects_,而不是_variables_,所以'numb.next!'将完全等于'1.next!',就是说,它会改变1等于2_。 '++'稍微好一些,因为它可能是一个赋值的语法糖,但是我个人更喜欢当前使用'='完成所有赋值的语法。 – philomory 2016-08-12 01:16:39

-3

检查这些运营商从C-家庭Ruby的IRB和测试他们自己:

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

这显然是错误的,并且不起作用,因为'(x ++)'在Ruby中是无效的语句。 – anothermh 2016-03-10 22:58:53

2

而在大卫黑色的从他的著作“基础扎实Rubyist”的话来说:

Ruby中的一些对象作为立即值存储在变量中。这些包括整数,符号(看起来像:this)和特殊对象true,false和 nil。当您将这些值中的一个赋值给变量(x = 1)时,该变量本身保留 ,而不是对其的引用。 实际上,这并不重要(在本书的参考文献和相关主题的讨论中,它通常会被隐含地留下,而不是重复地指出)。 Ruby自动处理对象引用的取消引用;你不必 做任何额外的工作来发送消息到一个对象,该对象包含一个字符串的引用,而不是一个包含立即整数值的对象。 但是直接值表示规则有一些有趣的分支,特别是当涉及到整数时。首先,任何代表 作为立即值的对象始终是完全相同的对象,无论它分配了多少个 变量。只有一个对象100,只有一个对象为false,以及 等等。 整数绑定变量的直接,唯一的本质是Ruby缺少 之前和之后的增量操作符 - 也就是说,您不能在Ruby中这样做: x = 1 x ++#没有这样的运算符 原因在于,由于1中x的即时存在,x ++就像1 ++, ,这意味着您会将数字1更改为数字2,这使得 没有意义。

+0

但是你怎么能做到“1.next”呢? – Magne 2016-12-03 15:08:58

相关问题