Scala 中的自增 (++) 运算符

发布于 2024-09-28 16:31:33 字数 97 浏览 1 评论 0原文

Scala 默认不支持 ++ 运算符来增加基本类型有什么原因吗? 例如,你不能写:

var i=0
i++

谢谢

Is there any reason for Scala not support the ++ operator to increment primitive types by default?
For example, you can not write:

var i=0
i++

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

情仇皆在手 2024-10-05 16:31:33

我的猜测是这被省略了,因为它只适用于可变变量,并且对于不可变值没有意义。也许已经决定 ++ 运算符不会尖叫赋值,因此包含它可能会导致关于是否正在改变变量的错误。

我觉得这样的事情是安全的(一行):

i++

但这将是一种不好的做法(在任何语言中):

var x = i++

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

My guess is this was omitted because it would only work for mutable variables, and it would not make sense for immutable values. Perhaps it was decided that the ++ operator doesn't scream assignment, so including it may lead to mistakes with regard to whether or not you are mutating the variable.

I feel that something like this is safe to do (on one line):

i++

but this would be a bad practice (in any language):

var x = i++

You don't want to mix assignment statements and side effects/mutation.

苏别ゝ 2024-10-05 16:31:33

我喜欢 Craig答案,但我认为必须更强烈地阐明这一点。

  1. “基元”——如果 Int 可以做到这一点,那么用户制作的 Complex 也可以(例如)。

  2. ++ 的基本用法如下:

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

    x++

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

这将需要新的语言功能。例如,假设我们创建一个 assign 关键字。类型签名也需要更改,以表明 ++ 不是返回一个Complex,而是分配 em> 它到保存当前对象的任何字段。本着 Scala 不侵入程序员命名空间的精神,假设我们通过在类型前添加 @ 来做到这一点。

那么它可能是这样的:

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
}

由于 Scala 规则,这与:

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

这不是意图。现在,Scala 提供了一种流畅的风格:obj method param method param method param ...。这将 C++/Java 对象方法参数的传统语法与通过多个函数对输入进行管道化以获得最终结果的函数式编程概念完美地结合在一起。这种风格最近也被称为“流畅的界面”。

问题是,通过赋予这种风格特权,它会削弱后缀运算符(以及前缀运算符,但 Scala 几乎没有它们)。因此,最终,Scala 必须做出重大改变,并且无论如何它都能够达到 C/Java 递增和递减运算符的优雅性——除非它真的偏离了它所做的事情支持。

I like Craig's answer, but I think the point has to be more strongly made.

  1. There are no "primitives" -- if Int can do it, then so can a user-made Complex (for example).

  2. Basic usage of ++ would be like this:

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

    x++

  3. How do you implement ++ in class Complex? Assuming that, like Int, the object is immutable, then the ++ method needs to return a new object, but that new object has to be assigned.

It would require a new language feature. For instance, let's say we create an assign keyword. The type signature would need to be changed as well, to indicate that ++ is not returning a Complex, but assigning it to whatever field is holding the present object. In Scala spirit of not intruding in the programmers namespace, let's say we do that by prefixing the type with @.

Then it could be like this:

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

The next problem is that postfix operators suck with Scala rules. For instance:

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

Because of Scala rules, that is the same thing as:

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

Which wasn't the intent. Now, Scala privileges a flowing style: obj method param method param method param .... That mixes well C++/Java traditional syntax of object method parameter with functional programming concept of pipelining an input through multiple functions to get the end result. This style has been recently called "fluent interfaces" as well.

The problem is that, by privileging that style, it cripples postfix operators (and prefix ones, but Scala barely has them anyway). So, in the end, Scala would have to make big changes, and it would be able to measure up to the elegance of C/Java's increment and decrement operators anyway -- unless it really departed from the kind of thing it does support.

々眼睛长脚气 2024-10-05 16:31:33

在Scala中,++是一个有效的方法,没有方法意味着赋值。只有 = 可以做到这一点。

更长的答案是,像 C++ 和 Java 这样的语言会特殊对待 ++,而 Scala 会特殊对待 =,而且方式不一致。

在 Scala 中,当您编写 i += 1 时,编译器首先在 Int 上查找名为 += 的方法。它不在那里,所以接下来它会在 = 上发挥作用,并尝试编译该行,就好像它读取 i = i + 1 一样。如果您编写 i++,那么 Scala 将调用 i 上的方法 ++ 并将结果分配给...无。因为只有=表示赋值。您可以编写 i ++= 1 但这样就达不到目的了。

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

In Scala, ++ is a valid method, and no method implies assignment. Only = can do that.

A longer answer is that languages like C++ and Java treat ++ specially, and Scala treats = specially, and in an inconsistent way.

In Scala when you write i += 1 the compiler first looks for a method called += on the Int. It's not there so next it does it's magic on = and tries to compile the line as if it read i = i + 1. If you write i++ then Scala will call the method ++ on i and assign the result to... nothing. Because only = means assignment. You could write i ++= 1 but that kind of defeats the purpose.

The fact that Scala supports method names like += is already controversial and some people think it's operator overloading. They could have added special behavior for ++ but then it would no longer be a valid method name (like =) and it would be one more thing to remember.

-残月青衣踏尘吟 2024-10-05 16:31:33

我认为部分原因是 +=1 只是多了一个字符,而 ++ 在集合代码中大量用于连接。所以它使代码保持干净。

此外,Scala 鼓励不可变变量,而 ++ 本质上是一种变异操作。如果您需要+=,至少您可以强制所有突变都经过通用的赋值过程(例如def a_=)。

I think the reasoning in part is that +=1 is only one more character, and ++ is used pretty heavily in the collections code for concatenation. So it keeps the code cleaner.

Also, Scala encourages immutable variables, and ++ is intrinsically a mutating operation. If you require +=, at least you can force all your mutations to go through a common assignment procedure (e.g. def a_=).

聽兲甴掵 2024-10-05 16:31:33

主要原因是 Scala 中不需要,就像 C 中那样。在 C 中,您不断地:

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

C++ 添加了更高级别的方法来避免显式循环,但 Scala 更进一步提供了 foreach、map、flatMap FoldLeft 等。即使您实际上想要对整数序列进行操作,而不仅仅是循环访问非整数对象的集合,您也可以使用 Scala range。

(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 时,我后来找到了更好的方法,但不需要它。

The primary reason is that there is not the need in Scala, as in C. In C you are constantly:

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

C++ has added higher level methods for avoiding for explicit loops, but Scala has much gone further providing foreach, map, flatMap foldLeft etc. Even if you actually want to operate on a sequence of Integers rather than just cycling though a collection of non integer objects, you can use Scala range.

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

Because the ++ operator is used by the collection library, I feel its better to avoid its use in non collection classes. I used to use ++ as a value returning method in my Util package package object as so:

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     
}

But I removed it. Most of the times when I have used ++ or + 1 on an integer, I have later found a better way, which doesn't require it.

一百个冬季 2024-10-05 16:31:33

如果您定义自己的类可以模拟所需的输出,这是可能的,但是如果您也想使用普通的“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
}

一些可能的测试用例

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

It is possible if you define you own class which can simulate the desired output however it may be a pain if you want to use normal "Int" methods as well since you would have to always use *()

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
}

Some possible test cases

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
怪异←思 2024-10-05 16:31:33

当然,如果你真的想要的话,你可以在 Scala 中使用它:

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

Of course you can have that in Scala, if you really want:

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

And here you go:

scala> runProgram
runProgram: Int = 3
忆梦 2024-10-05 16:31:33

没有包含它是因为 Scala 开发人员认为它使规范变得更加复杂,同时只实现了微不足道的好处,而且 Scala 根本没有运算符。

你可以这样写你自己的:

class PlusPlusInt(i: Int){
  def ++ = i+1
  }

implicit def int2PlusPlusInt(i: Int) = new PlusPlusInt(i)

val a = 5++
// a is 6

但我确信你会遇到一些优先级不按预期工作的麻烦。另外,如果添加 i++,人们也会要求 ++i,这并不真正适合 Scala 的语法。

It isn't included because Scala developers thought it make the specification more complex while achieving only negligible benefits and because Scala doesn't have operators at all.

You could write your own one like this:

class PlusPlusInt(i: Int){
  def ++ = i+1
  }

implicit def int2PlusPlusInt(i: Int) = new PlusPlusInt(i)

val a = 5++
// a is 6

But I'm sure you will get into some trouble with precedence not working as you expect. Additionally if i++ would be added, people would ask for ++i too, which doesn't really fit into Scala's syntax.

失去的东西太少 2024-10-05 16:31:33

让我们定义一个 var:

var i = 0

++i 已经足够短了:

{i+=1;i}

现在 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;

当然,风格可能取决于。

Lets define a var:

var i = 0

++i is already short enough:

{i+=1;i}

Now i++ can look like this:

i(i+=1)

To use above syntax, define somewhere inside a package object, and then import:

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

Operators chaining is also possible:

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

The above example is similar to this Java (C++?) code:

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

The style could depend, of course.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文