Оператор увеличения (++) в Scala - PullRequest
53 голосов
/ 22 октября 2010

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

var i=0
i++

Спасибо

Ответы [ 9 ]

34 голосов
/ 22 октября 2010

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

Я чувствую, что нечто подобное безопасноdo (в одну строку):

i++

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

var x = i++

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

33 голосов
/ 22 октября 2010

Мне нравится Крейг * ответ , но я думаю, что смысл должен быть более решительным.

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

  2. Базовое использование ++ будет выглядеть так:

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

    x++

  3. Как реализовать ++ в классе 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 .... Это хорошо сочетает традиционный синтаксис C ++ / Java object method parameter с концепцией функционального программирования, заключающейся в конвейерной обработке ввода через несколько функций для получения конечного результата. Этот стиль также недавно назывался «плавными интерфейсами».

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

19 голосов
/ 22 октября 2010

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

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

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

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

12 голосов
/ 22 октября 2010

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

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

2 голосов
/ 17 ноября 2016

Это возможно, если вы определите свой собственный класс, который может имитировать желаемый результат, однако это может быть неприятно, если вы хотите использовать обычные методы "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
2 голосов
/ 31 октября 2012

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

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

C ++ добавил методы более высокого уровня для избежания явных циклов, но Scala имеетМногое пошло дальше, предоставляя foreach, map, flatMap foldLeft и т. д. Даже если вы на самом деле хотите работать с последовательностью целых чисел, а не просто ездить на велосипеде через коллекцию нецелых объектов, вы можете использовать диапазон Scala.* Поскольку оператор ++ используется библиотекой коллекций, я чувствую, что лучше избегать его использования в не коллекционных классах.Я использовал ++ в качестве метода возврата значения в моем объекте пакета пакета 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 для целого числа, я позже нашел лучший способ, который не требует этого.

2 голосов
/ 23 декабря 2010

Конечно, вы можете иметь это в 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
0 голосов
/ 30 сентября 2012

Позволяет определить переменную:

var i = 0

++ Я уже достаточно короткий:

{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;

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

0 голосов
/ 22 октября 2010

Он не включен, потому что разработчики 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.

...