program story

Scala의 증분 (++) 연산자

inputbox 2021. 1. 7. 07:56
반응형

Scala의 증분 (++) 연산자


기본적으로 기본 유형을 증가시키기 위해 Scala가 ++ 연산자를 지원하지 않는 이유가 있습니까? 예를 들어 다음과 같이 쓸 수 없습니다.

var i=0
i++

감사


내 생각 엔 이것은 변경 가능한 변수에 대해서만 작동하고 변경 불가능한 값에는 의미가 없기 때문에 생략되었습니다. ++운영자가 할당을 비명을 지르지 않기로 결정 했을 수 있으므로 변수를 변경하는지 여부와 관련하여 실수로 이어질 수 있습니다.

나는 이와 같은 일이 안전하다고 생각합니다 (한 줄로).

i++

그러나 이것은 (모든 언어에서) 나쁜 습관입니다.

var x = i++

할당 문과 부작용 / 돌연변이를 혼합하고 싶지 않습니다.


나는 Craig대답을 좋아 하지만, 요점은 더 강하게 만들어야한다고 생각합니다.

  1. "기본 요소"는 없습니다. 가능하다면 Int사용자가 만든 것도 가능합니다 Complex(예를 들어).

  2. 의 기본 사용법 ++은 다음과 같습니다.

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

    x++

  3. ++수업에서 어떻게 구현 Complex합니까? Int객체가 불변 이라고 가정하면 ++메서드는 객체 를 반환해야 하지만 해당 새 객체를 할당해야 합니다.

새로운 언어 기능이 필요합니다. 예를 들어 assign키워드를 생성한다고 가정 해 보겠습니다 . 유형 서명은 그 나타 내기 위해,뿐만 아니라 변경 될 필요가 ++되지 않는 반환Complex하지만, 할당 본 개체를 들고 어떤 필드에. 프로그래머 네임 스페이스에 침입하지 않는다는 스칼라의 정신에서 타입 앞에 @.

그러면 다음과 같을 수 있습니다.

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

다음 문제는 접미사 연산자가 스칼라 규칙에 문제가 있다는 것입니다. 예를 들면 :

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

Scala 규칙 때문에 다음과 같습니다.

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

의도가 아니 었습니다. 이제 Scala는 유동적 인 스타일 : obj method param method param method param .... 그것은 object method parameter최종 결과를 얻기 위해 여러 함수를 통해 입력을 파이프 라이닝하는 함수 프로그래밍 개념과 C ++ / Java의 전통적인 구문을 잘 혼합합니다 . 이 스타일은 최근 "유창한 인터페이스"라고도 불립니다.

문제는 그 스타일을 특권으로 사용함으로써 접미사 연산자 (그리고 접두사 연산자도 불구가되지만 스칼라가 거의 가지고 있지 않다는 것입니다). 그래서, 결국, 스칼라는 큰 변화를 만들어야 할 것이고, 어쨌든 C / 자바의 증가 및 감소 연산자의 우아함까지 측정 할 수있을 것입니다 - 정말이 물건의 종류에서 출발하지 않는 한 수행 을 지원.


Scala에서 ++는 유효한 메서드이며 할당을 의미하는 메서드는 없습니다. =그렇게 할 수 있습니다.

더 긴 대답은 C ++ 및 Java와 같은 언어 ++=특별하게 취급하고 Scala는 특별하고 일관성없는 방식으로 취급 한다는 것입니다.

Scala i += 1에서 컴파일러 를 작성할 때 먼저 +=Int에서 호출 메서드를 찾습니다 . 그것은 거기에 없기 때문에 다음에 그것은 마술을 =하고 마치 읽은 것처럼 라인을 컴파일하려고합니다 i = i + 1. 작성 i++하면 Scala는 메서드 ++호출 i하고 결과를 ... 아무것도 할당하지 않습니다. 단지 =할당을 의미 하기 때문 입니다. 글을 쓸 수는 i ++= 1있지만 그런 종류는 목적에 맞지 않습니다.

Scala가 같은 메서드 이름을 지원한다는 사실 +=은 이미 논란의 여지가 있으며 일부 사람들은 그것이 연산자 오버로딩이라고 생각합니다. 에 대한 특별한 동작을 추가 할 수 ++있었지만 더 이상 유효한 메서드 이름 (예 :)이 아니며 =기억해야 할 한 가지가 더 있습니다.


부분적으로 추론은 +=1하나 이상의 문자이며 ++연결을 위해 컬렉션 코드에서 상당히 많이 사용 된다는 것 입니다 . 따라서 코드를 깔끔하게 유지합니다.

또한 Scala는 변경 불가능한 변수를 권장하며 ++본질적으로 변경 작업입니다. 필요한 경우 +=최소한 모든 돌연변이가 공통 할당 절차 (예 :)를 거치도록 강제 할 수 있습니다 def a_=.


물론 원하는 경우 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

주된 이유는 C에서와 같이 Scala에는 필요가 없기 때문입니다. C에서는 지속적으로 다음을 수행합니다.

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

C ++는 명시 적 루프를 피하기 위해 더 높은 수준의 메서드를 추가했지만 Scala는 foreach, map, flatMap foldLeft 등을 훨씬 더 많이 제공했습니다. 실제로 정수가 아닌 개체의 컬렉션을 순환하는 것보다 정수 시퀀스에서 작동하려는 경우에도 마찬가지입니다. , 스칼라 범위를 사용할 수 있습니다.

(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
}

가능한 테스트 사례

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는 이미 충분히 짧습니다.

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

물론 스타일은 달라질 수 있습니다.


Scala 개발자는 무시할만한 이점 만 달성하면서 사양을 더 복잡하게 만들고 Scala에는 연산자가 전혀 없기 때문에 포함되지 않았습니다.

다음과 같이 직접 작성할 수 있습니다.

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.

ReferenceURL : https://stackoverflow.com/questions/3992399/increment-operator-in-scala

반응형