Program Tip

스칼라로 반환

programtip 2020. 11. 7. 10:24
반응형

스칼라로 반환


저는 초보자 스칼라 프로그래머이며 이상한 행동을 보았습니다.

def balanceMain(elem: List[Char]): Boolean =
  {
    if (elem.isEmpty)
      if (count == 0)
        true;
      else false;

    if (elem.head == '(')
      balanceMain(elem.tail, open, count + 1);....

위의 기본적으로 true if elem.isEmptycount == 0. 그렇지 않으면 false를 반환하고 싶습니다.

이제 위에서 나는 스칼라에 return 문을 추가 할 필요가 없다는 것을 읽었습니다. 그래서 return위에서 생략했습니다 . 그러나 부울을 반환하지 않습니다. return 문을 return true. 완벽하게 작동합니다. 왜 그래야만하지?

또한 스칼라에서 return 문을 사용하는 것이 왜 나쁜 습관으로 간주됩니까?


return키워드를 생략하는 것만 큼 간단하지 않습니다 . Scala에서 없으면 return마지막 표현식이 반환 값으로 사용됩니다. 따라서 마지막 표현식이 반환하려는 것이라면 return키워드를 생략 할 수 있습니다 . 그러나 반환하려는 것이 마지막 표현식 아닌 경우 Scala 반환하려는 것을 알지 못합니다 .

예 :

def f() = {
  if (something)
    "A"
  else
    "B"
}

여기서 함수의 마지막 표현식은 f문자열로 평가되는 if / else 표현식입니다. 명시 적으로 return표시 되지 않았기 때문에 Scala는이 if / else 표현식의 결과 인 문자열을 반환하기를 원한다고 추론합니다.

이제 if / else 표현식 뒤에 무언가를 추가 하면 :

def f() = {
  if (something)
    "A"
  else
    "B"

  if (somethingElse)
    1
  else
    2
}

이제 마지막 표현식은 Int로 평가되는 if / else 표현식입니다. 따라서의 반환 유형은 fInt입니다. 우리가 정말로 String을 반환하기를 원했다면, Scala는 그것이 우리가 의도 한 것이 무엇인지 알지 못 하기 때문에 문제가됩니다 . 따라서 문자열을 변수에 저장하고 두 번째 if / else 표현식 다음에 반환하거나 순서를 변경하여 문자열 부분이 마지막에 발생하도록 수정해야합니다.

마지막으로 다음 return과 같이 중첩 된 if-else 표현식으로도 키워드를 피할 수 있습니다.

def f() = {
  if(somethingFirst) {
    if (something)      // Last expression of `if` returns a String
     "A"
    else
     "B"
  }
  else {
    if (somethingElse)
      1
    else
      2

    "C"                // Last expression of `else` returns a String
  }

}


이 주제는 지금까지 답변에서 설명한 것처럼 실제로 조금 더 복잡합니다. Rob Norris 의이 블로그 게시물은를 더 자세히 설명하고 return을 사용하면 실제로 코드가 손상되거나 적어도 분명하지 않은 효과가있는 경우에 대한 예를 제공합니다.

At this point let me just quote the essence of the post. The most important statement is right in the beginning. Print this as a poster and put it to your wall :-)

The return keyword is not “optional” or “inferred”; it changes the meaning of your program, and you should never use it.

It gives one example, where it actually breaks something, when you inline a function

// Inline add and addR
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add

scala> sum(33, 42, 99)
res2: Int = 174 // alright

def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR

scala> sumR(33, 42, 99)
res3: Int = 33 // um.

because

A return expression, when evaluated, abandons the current computation and returns to the caller of the method in which return appears.

This is only one of the examples given in the linked post and it's the easiest to understand. There're more and I highly encourage you, to go there, read and understand.

When you come from imperative languages like Java, this might seem odd at first, but once you get used to this style it will make sense. Let me close with another quote:

If you find yourself in a situation where you think you want to return early, you need to re-think the way you have defined your computation.


I don't program Scala, but I use another language with implicit returns (Ruby). You have code after your if (elem.isEmpty) block -- the last line of code is what's returned, which is why you're not getting what you're expecting.

EDIT: Here's a simpler way to write your function too. Just use the boolean value of isEmpty and count to return true or false automatically:

def balanceMain(elem: List[Char]): Boolean =
{
    elem.isEmpty && count == 0
}

Don't write if statements without a corresponding else. Once you add the else to your fragment you'll see that your true and false are in fact the last expressions of the function.

def balanceMain(elem: List[Char]): Boolean =
  {
    if (elem.isEmpty)
      if (count == 0)
        true
      else
        false
    else
      if (elem.head == '(')
        balanceMain(elem.tail, open, count + 1)
      else....

By default the last expression of a function will be returned. In your example there is another expression after the point, where you want your return value. If you want to return anything prior to your last expression, you still have to use return.

You could modify your example like this, to return a Boolean from the first part

def balanceMain(elem: List[Char]): Boolean = {
  if (elem.isEmpty) {
    // == is a Boolean resulting function as well, so your can write it this way
    count == 0
  } else {
    // keep the rest in this block, the last value will be returned as well
    if (elem.head == "(") {
      balanceMain(elem.tail, open, count + 1)
    }
    // some more statements
    ...
    // just don't forget your Boolean in the end
    someBoolExpression
  }
}

Use case match for early return purpose. It will force you to declare all return branches explicitly, preventing the careless mistake of forgetting to write return somewhere.

참고URL : https://stackoverflow.com/questions/12560463/return-in-scala

반응형