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.