Подтвердить что ты не робот

Вернитесь в Scala

Я новичок scala программист и наткнулся на странное поведение.

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, если elem.isEmpty и count == 0. В противном случае я хочу вернуть false.

Теперь выше я прочитал, что нет необходимости добавлять оператор return в scala. Поэтому я опустил return выше. Но он не возвращает логическое значение. Если я добавлю оператор return как return true. он работает отлично. Почему это так?

Кроме того, почему считается, что плохая практика имеет операторы возврата в scala

4b9b3361

Ответ 1

Это не так просто, как просто опустить ключевое слово return. В Scala, если нет return, то последним выражением считается возвращаемое значение. Итак, если последнее выражение - это то, что вы хотите вернуть, вы можете опустить ключевое слово return. Но если то, что вы хотите вернуть, не является последним выражением, тогда Scala не будет знать, что вы хотите вернуть его.

Пример:

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

Здесь последнее выражение функции f является выражением if else, которое вычисляется как String. Поскольку не указано явное return, Scala выведет, что вы хотите вернуть результат этого выражения if/else: a String.

Теперь, если мы добавим что-то после выражения if/else:

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

  if (somethingElse)
    1
  else
    2
}

Теперь последнее выражение является выражением if/else, которое вычисляется как Int. Таким образом, тип возврата f будет Int. Если бы мы действительно хотели, чтобы он возвращал String, то у нас были проблемы, потому что Scala имеет не идею, что мы намеревались. Таким образом, мы должны исправить это, либо сохраняя String для переменной, и возвращая ее после второго выражения if/else, либо изменив порядок, чтобы последняя была последней.

Наконец, мы можем избежать ключевого слова return даже с вложенным выражением if-else, например yours:

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
  }

}

Ответ 2

Этот вопрос на самом деле немного сложнее, как описано в ответах до сих пор. Этот блог Rob Norris объясняет это более подробно и дает примеры, когда использование return действительно нарушит ваш код (или, по крайней мере, будет иметь неочевидные эффекты).

В этот момент позвольте мне просто процитировать суть поста. Самое главное утверждение в самом начале. Распечатайте это как плакат и положите его на стену: -)

Ключевое слово return не является "необязательным" или "выводимым"; он меняет смысл вашей программы, и вы никогда не должны ее использовать.

Он дает один пример, где он действительно что-то ломает, когда вы встраиваете функцию

// 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.

потому что

A return выражение, когда оценивается, отказывается от текущего вычисления и возвращается к вызывающей стороне метода, в котором появляется return.

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

Когда вы приходите с императивных языков, таких как Java, сначала это может показаться странным, но как только вы привыкнете к этому стилю, это будет иметь смысл. Позвольте мне закрыть еще одну цитату:

Если вы окажетесь в ситуации, когда, как вы думаете, хотите вернуться раньше, вам нужно подумать о том, как вы определили свои вычисления.

Ответ 3

Я не программирую Scala, но я использую другой язык с неявным возвратом (Ruby). У вас есть код после блока if (elem.isEmpty) - последняя строка кода - это то, что было возвращено, поэтому вы не получаете то, что ожидаете.

EDIT: здесь более простой способ написать свою функцию. Просто используйте логическое значение isEmpty и count, чтобы автоматически вернуть true или false:

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

Ответ 4

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

Вы можете изменить свой пример следующим образом, чтобы вернуть Boolean из первой части

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

Ответ 5

Не записывайте операторы if без соответствующего else. Когда вы добавите else в свой фрагмент, вы увидите, что ваши true и false на самом деле являются последними выражениями функции.

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....