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

发布于 2024-09-02 05:21:57 字数 532 浏览 6 评论 0原文

在 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

为什么?

In Scala 2.8.0 RC 2 this definition:

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

gives the error message:

not found: value t

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

gives

missing parameter type for expanded function ((x$1) => x$1{}.toString{}){}

Only this works:

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

Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冬天的雪花 2024-09-09 05:21:57

这些都可以工作,无需类型注释:

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 演示

Either of these work, without type annotation:

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

But why don't your variations work?

The first one actually isn't valid Scala in any context:

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

The second expression _.toString uses the placeholder syntax for anonymous functions, and only works if the expression has an expected type.

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

The problem is that the default expression for a parameter whose type depends an type parameter doesn't have an expected type. This seems counter-intuitive, why wouldn't it have the declared type of the argument as the expected type? It turns out that the expression can have a more specific type, and that type checking is deferred to the 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]()

If the type of textProvider doesn't include the type parameter T, the default expression has an expected type, and you can use the placeholder syntax:

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

For a detailed explanation of the design of named and default parameters, I recommend Lucas Rytz's Scala Days presentation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文