++运算符在斯卡拉
Scala是否有任何理由不支持++运算符默认增加原始types? 例如,你不能写:
var i=0 i++
谢谢
我的猜测是这个被省略,因为它只适用于可变variables,并且对于不可变的值是没有意义的。 也许有人认为++
运算符不会尖叫,所以包含它可能会导致错误,无论你是否在variables变异。
我觉得这样做是安全的(在一条线上):
i++
但这将是一个不好的做法(用任何语言):
var x = i++
你不想混合赋值语句和副作用/变异。
我喜欢克雷格的回答 ,但我认为这一点必须更强烈。
-
没有“基元” – 如果
Int
可以做到的话,那么用户自制的Complex
也可以。 -
++
基本用法是这样的:var x = 1 // or Complex(1, 0)
x++
-
你如何在类
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的语法。