代码之家  ›  专栏  ›  技术社区  ›  Alexey Romanov

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

  •  1
  • Alexey Romanov  · 技术社区  · 15 年前

    在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 回复  |  直到 15 年前
        1
  •  4
  •   retronym    15 年前

    这些工作中的任何一个,没有类型注释:

    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 .