++运算符在斯卡拉

Scala是否有任何理由不支持++运算符默认增加原始types? 例如,你不能写:

var i=0 i++ 

谢谢

我的猜测是这个被省略,因为它只适用于可变variables,并且对于不可变的值是没有意义的。 也许有人认为++运算符不会尖叫,所以包含它可能会导致错误,无论你是否在variables变异。

我觉得这样做是安全的(在一条线上):

 i++ 

但这将是一个不好的做法(用任何语言):

 var x = i++ 

你不想混合赋值语句和副作用/变异。

我喜欢克雷格的回答 ,但我认为这一点必须更强烈。

  1. 没有“基元” – 如果Int可以做到的话,那么用户自制的Complex也可以。

  2. ++基本用法是这样的:

    var x = 1 // or Complex(1, 0)

    x++

  3. 你如何在类Complex实现++ ? 假设像Int一样,对象是不可变的,那么++方法需要返回一个对象,但是这个新对象必须被赋值

这将需要一个新的语言function。 例如,假设我们创build一个assign关键字。 types签名也需要被改变,以表明++不是返回一个Complex ,而是分配给任何持有当前对象的字段。 在Scala的精神不侵犯程序员的名字空间,让我们说,我们做了这样的前缀types@

那么它可能是这样的:

 case class Complex(real: Double = 0, imaginary: Double = 0) { def ++: @Complex = { assign copy(real = real + 1) // instead of return copy(real = real + 1) } 

接下来的问题是后缀操作符吸引Scala规则。 例如:

 def inc(x: Int) = { x++ x } 

由于斯卡拉规则,这是一样的事情:

 def inc(x: Int) = { x ++ x } 

这不是意图。 现在,Scala赋予stream畅的风格: obj method param method param method param ...object method parameter C ++ / Java传统语法和通过多个函数stream水线化input的函数式编程概念混合得到最终结果。 这种风格最近也被称为“stream畅接口”。

问题是,通过特权这种风格,它削弱了后缀运算符(和前缀的,但斯卡拉勉强拥有它们)。 所以,最后,Scala将不得不做出巨大的改变,它将能够衡量C / Java的增量和减量运算符的优雅程度 – 除非它真的离开了它所支持的那种东西。

在斯卡拉,++是一个有效的方法,没有方法意味着分配。 只有=可以做到这一点。

更长的答案是像C ++和Java这样的++专门处理++ ,而Scala则专门处理=并且以不一致的方式处理。

在Scala中编写i += 1 ,编译器首先在Int上查找名为+=的方法。 它不在那里,所以接下来它就是=上的魔法,并试图编译该行,就像读取i = i + 1 。 如果你写i++那么Scala会调用i的方法++ ,并把结果赋给…什么都不是。 因为只有=意味着分配。 你可以写i ++= 1但是这种方式打破了目的。

Scala支持像+=这样的方法名的事实已经引起争议,有些人认为它是运算符重载。 他们可能为++添加了特殊的行为,但不再是一个有效的方法名称(如= ),还有一件事要记住。

我认为推理的部分原因是+=1只是一个字符, ++在集合代码中用于连接。 所以它保持代码更清洁。

另外,Scala鼓励不可变的variables,而++本质上是一个变异的操作。 如果你需要+= ,至less你可以强迫所有的突变通过一个通用的赋值程序(例如def a_= )。

当然,如果你真的想要,你可以在斯卡拉

 import scalaz._ import Scalaz._ case class IncLens[S,N](lens: Lens[S,N], num : Numeric[N]) { def ++ = lens.mods(num.plus(_, num.one)) } implicit def incLens[S,N:Numeric](lens: Lens[S,N]) = IncLens[S,N](lens, implicitly[Numeric[N]]) val i = Lens[Int,Int](identity, (x, y) => y) val imperativeProgram = for { _ <- i := 0; _ <- i++; _ <- i++; x <- i++ } yield x def runProgram = imperativeProgram ! 0 

在这里你去:

 scala> runProgram runProgram: Int = 3 

主要的原因是在Scala中不需要像C中那样。在C中你总是:

 for(i = 0, i < 10; i++) { //Do stuff } 

C ++已经添加了更高层次的方法来避免显式循环,但是Scala已经进一步提供了foreach,map,flatMap,foldLeft等等。即使你真的想要在一个整数序列上进行操作,而不是仅仅循环一些非整型对象,你可以使用Scala范围。

 (1 to 5) map (_ * 3) //Vector(3, 6, 9, 12, 15) (1 to 10 by 3) map (_ + 5)//Vector(6, 9, 12, 15) 

因为集合库使用++运算符,所以我最好避免在非集合类中使用它。 我曾经在我的Util包中使用++作为返回值的方法,如下所示:

 implicit class RichInt2(n: Int) { def isOdd: Boolean = if (n % 2 == 1) true else false def isEven: Boolean = if (n % 2 == 0) true else false def ++ : Int = n + 1 def -- : Int = n - 1 } 

但我删除了它。 大多数情况下,当我在一个整数上使用++或+ 1时,我后来发现了一个更好的方法,这并不需要它。

如果你定义你自己的类,它可以模拟所需的输出是可能的,但是如果你想使用普通的“Int”方法也是一种痛苦,因为你必须总是使用*()

 import scala.language.postfixOps //otherwise it will throw warning when trying to do num++ /* * my custom int class which can do ++ and -- */ class int(value: Int) { var mValue = value //Post-increment def ++(): int = { val toReturn = new int(mValue) mValue += 1 return toReturn } //Post-decrement def --(): int = { val toReturn = new int(mValue) mValue -= 1 return toReturn } //a readable toString override def toString(): String = { return mValue.toString } } //Pre-increment def ++(n: int): int = { n.mValue += 1 return n; } //Pre-decrement def --(n: int): int = { n.mValue -= 1 return n; } //Something to get normal Int def *(n: int): Int = { return n.mValue } 

一些可能的testing用例

 scala>var num = new int(4) num: int = 4 scala>num++ res0: int = 4 scala>num res1: int = 5 // it works although scala always makes new resources scala>++(num) //parentheses are required res2: int = 6 scala>num res3: int = 6 scala>++(num)++ //complex function res4: int = 7 scala>num res5: int = 8 scala>*(num) + *(num) //testing operator_* res6: Int = 16 

让我们定义一个var:

 var i = 0 

++我已经够短了:

 {i+=1;i} 

现在我可以看起来像这样:

 i(i+=1) 

要使用上面的语法,请在包对象内定义某处,然后导入:

 class IntPostOp(val i: Int) { def apply(op: Unit) = { op; i } } implicit def int2IntPostOp(i: Int): IntPostOp = new IntPostOp(i) 

操作员链接也是可能的:

 i(i+=1)(i%=array.size)(i&=3) 

上面的例子类似于这个Java(C ++?)代码:

 i=(i=i++ %array.length)&3; 

当然,风格可能取决于。

这不包括在内,因为Scala开发人员认为它使规范更复杂,实现微乎其微的好处,因为Scala根本没有运营商。

你可以写下你自己的一个:

 class PlusPlusInt(i: Int){ def ++ = i+1 } implicit def int2PlusPlusInt(i: Int) = new PlusPlusInt(i) val a = 5++ // a is 6 

但是我相信你会遇到一些麻烦,优先级不能按照你的预期工作。 另外,如果我join了i ++,人们也会要求++我也不适合Scala的语法。