Scala 2.8:将匿名函数的类型推断作为默认参数

时间:2010-05-20 09:44:05

标签: scala scala-2.8 named-parameters

在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 个答案:

答案 0 :(得分:4)

其中任何一项工作,没有类型注释:

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

问题是类型取决于类型参数的参数的默认表达式没有预期的类型。这似乎违反直觉,为什么它不会将声明的参数类型作为预期类型?事实证明,表达式可以具有更具体的类型,并且类型检查将延迟到调用站点:

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

有关命名和默认参数设计的详细说明,我推荐Lucas Rytz的Scala Days presentation