Scala 2.8: вывод типа анонимных функций в качестве параметров по умолчанию

В Scala 2.8.0 RC 2 это определение:

  def buttonGroup[T](values: Array[T], textProvider: T => String = (t: T => t.toString)) = ...

выдает сообщение об ошибке:

не найдено: значение t

  def buttonGroup[T](values: Array[T], textProvider: T => String = (_.toString)) = ...

дает

отсутствует тип параметра для расширенной функции ((x$1) => x$1{}.toString{}){}

Только это работает:

 textProvider: T => String = (_:T).toString

Зачем?

1 ответ

Решение

Любая из этих работ, без аннотации типа:

def buttonGroup[T](values: Array[T], textProvider: T => String = (t: T) => t.toString) = 0

def buttonGroup[T](values: Array[T], textProvider: T => String = {t: T => t.toString}) = 0

Но почему ваши варианты не работают?

Первый на самом деле не является действительным Scala в любом контексте:

scala> (t: Any => t.toString)
<console>:1: error: ';' expected but ')' found.
       (t: Any => t.toString))
                             ^

Второе выражение _.toString использует синтаксис заполнителя для анонимных функций и работает, только если выражение имеет ожидаемый тип.

scala> def foo[T] = { (_.toString) : (T => String) }
foo: [T](T) => String

Проблема в том, что выражение по умолчанию для параметра, тип которого зависит от параметра типа, не имеет ожидаемого типа. Это кажется нелогичным, почему бы не иметь объявленный тип аргумента в качестве ожидаемого типа? Оказывается, что выражение может иметь более конкретный тип, и что проверка типов откладывается до call-site:

scala> def foo[T](t: T = "string-t") = t
foo: [T](t: T)T

scala> foo(1)
res4: Int = 1

scala> foo()
res5: java.lang.String = string-t

scala> foo[Int]()
<console>:7: error: type mismatch;
 found   : java.lang.String
 required: Int
Error occurred in an application involving default arguments.
       foo[Int]()

Если тип textProvider не включает параметр типа Tвыражение по умолчанию имеет ожидаемый тип, и вы можете использовать синтаксис заполнителя:

scala> def buttonGroup[T](values: Array[T], textProvider: Any => String = _.toString) = 0
buttonGroup: [T](values: Array[T],textProvider: (Any) => String)Int

Для подробного объяснения дизайна именованных параметров и параметров по умолчанию я рекомендую презентацию Лукаса Ритца Scala Days.

Другие вопросы по тегам