Вывод простого типа в Scala - PullRequest
       10

Вывод простого типа в Scala

3 голосов
/ 07 октября 2009

Я смотрел на вывод типов в Scala, и есть пара вещей, которые я хотел бы немного лучше понять, почему типы выражения / метода-возврата должны быть явно объявлены в некоторых случаях.

Явное return объявление

Пример (работает, если ключевое слово return опущено):

def upCase(s: String) = {
  if (s.length == 0)
    return s    // COMPILE ERROR - forces return type of upCase to be declared.
  else
    s.toUpperCase()
}

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

Метод перегрузки

Пример (не компилируется при добавлении второго joiner метода):

def joiner(ss: List[String], sep: String) = ss.mkString(sep)

def joiner(ss: List[String]) = joiner(strings, " ")   // COMPILE ERROR WHEN ADDED

Ответы [ 5 ]

3 голосов
/ 07 октября 2009

Ну, самый очевидный ответ: потому что это указано в спецификации, см. Часть 6.20 справочника scala. Но почему это так задумано, действительно очень интересный вопрос. Я подозреваю, что это связано с тем, что компилятор не может предсказать, что выражение будет последним, так как return меняет поток выполнения.

EDIT:

Подумайте, не требуется ли для возврата явный тип возврата, следующий код:

def bar() = {   
  if(guard())  
    return "SS"  
  else if(gurard1())  
    return true   
  2  
}

что должен иметь тип возвращаемого значения в этой ситуации? Ну, есть вариант с наиболее распространенным супертипом, но я думаю, что это заставит нас возвращать Any во многих случаях. Ну, это только мои мысли, которые могут быть совершенно неверными =)

2 голосов
/ 07 октября 2009

Тип функции или метода выводится из типа его последнего оператора. Обычно это выражение.

Теперь "return" прерывает поток управления. Это, так сказать, «немедленное прерывание». Из-за этого обычные правила, используемые для определения типа выражения, больше не могут использоваться. Конечно, это все еще можно сделать, но я предполагаю, что цена за сложность компилятора считалась слишком высокой для возврата.

Вот пример того, как поток нарушается:

def toNumber(s: String) = {
  if (s == null)
    return ""

  if (s matches """\d+""")
    s.toInt
  else
    0
}

Обычно тип второго оператора if используется для определения типа всей функции. Но return в первом if вводит вторую точку возврата из функции, поэтому это правило не будет работать.

1 голос
/ 07 октября 2009

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

Ваш пример будет работать, если вы измените его на:

def upCase(s: String) = {
 if (s.length == 0)
   s    // note: no return
 else
   s.toUpperCase()
}

Я не знаю, почему возврат меняет это.

0 голосов
/ 08 октября 2009

Я подозреваю, что вывод о перегрузке (отсутствии) метода связан с аналогичной проблемой рекурсивных вызовов, потому что, если перегруженные методы не вызывают друг друга, он работает отлично:

  def joiner1(ss: List[String], sep: String) = ss.mkString(sep)
  def joiner(ss: List[String], sep: String) = ss.mkString(sep)
  def joiner(ss: List[String]) = joiner1(ss, " ")  

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

0 голосов
/ 07 октября 2009

Отказ от ответственности - этот ответ был направлен на вопрос в том виде, в котором он был первоначально размещен

Вывод типа Scala уже выводит тип возврата метода / выражения:

scala> def foo(s : String) = s + " Hello"
foo: (String)java.lang.String

scala> var t = foo("World")
t: java.lang.String = World Hello

и

scala> def bar( s : String) = s.toInt
bar: (String)Int

scala> var i = bar("3")
i: Int = 3

и:

scala> var j = if (System.getProperty("user.name") == "oxbow") 4 else "5".toInt
j: Int = 5

РЕДАКТИРОВАТЬ - я не осознавал, что включение ключевого слова return означало, что возвращаемый тип выражения должен был быть явно объявлен: я почти прекратил использовать return - но это интересный вопрос. Для примера joiner тип возвращаемого значения должен быть объявлен из-за перегрузки. Опять же, я не знаю подробностей о том, почему и было бы интересно узнать. Я подозреваю, что лучше сформулированная тема вопроса вызвала бы ответ от таких людей, как Джеймс Айри, Дэн Спивак или Даниэль Собрал.

...