Оператор Increment (++) в Scala

Есть ли какая-либо причина для Scala не поддерживать оператор ++ для приращения примитивных типов по умолчанию? Например, вы не можете писать:

var i=0
i++

Спасибо

Ответы

Ответ 1

Я предполагаю, что это было опущено, потому что оно будет работать только для изменяемых переменных, и это не имеет смысла для неизменных значений. Возможно, было решено, что оператор ++ не критикует назначение, поэтому включение его может привести к ошибкам в отношении того, изменяете ли вы переменную.

Я чувствую, что что-то вроде этого безопасно делать (на одной строке):

i++

но это будет плохой практикой (на любом языке):

var x = i++

Вы не хотите смешивать утверждения контировки и побочные эффекты/мутацию.

Ответ 2

Мне нравится Craig ответить, но я думаю, что этот вопрос должен быть более решительным.

  • Нет никаких "примитивов" - если Int может это сделать, тогда может быть пользовательский Complex (например).

  • Основное использование ++ будет таким:

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

    x++

  • Как вы реализуете ++ в классе Complex? Предполагая, что, как и Int, объект неизменен, тогда метод ++ должен возвращать новый объект, но этот новый объект должен быть назначен.

Для этого потребуется новая языковая функция. Например, предположим, что мы создаем ключевое слово assign. Также необходимо изменить сигнатуру типа, чтобы указать, что ++ не возвращает Complex, но назначает его любому полю, содержащему данный объект. В 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 .... Это хорошо сочетает традиционный синтаксис С++/Java object method parameter с концепцией функционального программирования конвейеризации ввода через несколько функций для получения конечного результата. Этот стиль недавно был назван "беглыми интерфейсами".

Проблема заключается в том, что, привилегируя этот стиль, он калечит постфиксные операторы (и префиксные, но Scala едва ли их вообще). Итак, в конце концов, Scala должен был бы внести большие изменения, и в любом случае он сможет измерить элегантность операторов приращения и уменьшения числа C/Java, если только он действительно не уйдет от того, что он поддерживает.

Ответ 3

В Scala, ++ является допустимым методом, и никакой метод не подразумевает назначение. Только = может это сделать.

Более длинный ответ заключается в том, что языки, такие как С++ и Java, относятся к ++ специально, а Scala относится к = специально и непоследовательно.

В Scala при написании i += 1 компилятор сначала ищет метод под названием += в Int. Это не так, так что теперь это волшебство на = и пытается скомпилировать строку так, как будто она читает i = i + 1. Если вы напишете i++, то Scala вызовет метод ++ на i и присвойте результат... ничего. Потому что только = означает назначение. Вы можете написать i ++= 1, но этот вид поражения цели.

Тот факт, что Scala поддерживает имена методов, такие как +=, уже вызывает противоречие, и некоторые люди считают его перегрузкой оператора. Они могли бы добавить специальное поведение для ++, но тогда оно больше не будет корректным именем метода (например, =), и это будет еще одна вещь, о которой нужно помнить.

Ответ 4

Я думаю, что рассуждение отчасти состоит в том, что +=1 - это еще один символ, а ++ используется довольно сильно в коде коллекций для конкатенации. Поэтому он сохраняет очиститель кода.

Кроме того, Scala поддерживает неизменяемые переменные, а ++ - внутренняя операция мутации. Если вам требуется +=, по крайней мере, вы можете заставить все свои мутации пройти общую процедуру назначения (например, def a_=).

Ответ 5

Конечно, вы можете иметь это в 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

Ответ 6

Основная причина в том, что в Scala нет необходимости, как в C. В C вы постоянно:

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

В С++ добавлены методы более высокого уровня, чтобы избежать явных циклов, но 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 для целого числа, я позже нашел лучший способ, который этого не требует.

Ответ 7

Возможно, если вы определите собственный класс, который может имитировать желаемый результат, но может быть больно, если вы хотите использовать обычные методы "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

Ответ 8

Позволяет определить 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 (С++?):

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

Конечно, стиль может зависеть.

Ответ 9

Он не включен, потому что разработчики Scala считали, что он делает сложную спецификацию при достижении лишь незначительных преимуществ и потому что Scala вообще не имеет операторов.

Вы можете написать свой собственный вот так:

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

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

val a = 5++
// a is 6

Но я уверен, что у вас возникнут проблемы с приоритетом, который не работает, как вы ожидаете. Кроме того, если я ++ будет добавлен, люди тоже будут запрашивать ++ i, что действительно не вписывается в синтаксис Scala.