在需要函数的位置使用构造函数

9

有两个简单的类,以 Int 作为参数:

case class Foo(i: Int)
     class Bar(j: Int)

我可以说:

List(1,2,3) map Foo

这段代码可行并且等效于更冗长的代码:

List(1,2,3) map {Foo(_)}

然而,Bar(因为它不是一个case类?)不能在相同的结构中使用:

List(1,2,3) map Bar

  error: not found: value Bar
          List(1,2,3) map Bar
                          ^

是否有一些特殊的语法可以引用任何构造函数并利用 eta 扩展?List(1,2,3) map {new Bar(_)} 看起来比 Foo 更加冗长。

1
Eta扩展是发生在方法中的事情。请注意,构造函数不是一个方法。 - Daniel C. Sobral
@DanielC.Sobral 什么是构造函数? - Ashkan Kh. Nazary
构造函数是一系列指令,用于初始化新分配的对象。 - Daniel C. Sobral
@DanielC.Sobral 那不是一个方法或函数吗?你不能显式地调用它,也不能传递它或应用 eta 扩展将其转换为函数吗? - Ashkan Kh. Nazary
@AshkanKh.Nazary 不行,你不能这样做。例如尝试使用 new String _。在字节码级别上也有所不同,并且在方法和构造函数之间的JVM期望中存在各种差异。 - Daniel C. Sobral
显示剩余2条评论
2个回答

12

在前一种情况下它能够工作,因为case类的伴生对象扩展了适当的FunctionN特质。 (在您的示例中为object Foo extends (Int => Foo))。对于非case类,您可以手动执行此操作:

scala> class Bar(i: Int)
defined class Bar

scala> class Bar(i: Int); object Bar extends (Int => Bar) { def apply(i: Int) = new Bar(i) }
defined class Bar
defined module Bar

scala> List(2, 3) map Bar
res17: List[Bar] = List(Bar@1f99e90, Bar@1191056)

在我看来,最好使用new Bar(_),因为额外的样板代码可能不值得为了少量简洁而付出代价。


2
有趣的是,我不知道一个 case class 扩展了 FunctionN。我记得在 Stack Overflow 上有一个答案列出了 case classes 的所有自动特性,但我不记得提到过这个问题。 - Peter Schmitz
1
案例类不会,它们的伴生对象会。 - missingfaktor

2

由于Foo是一个case类,因此还有一个名为Foo的伴生对象,它实现了Function1接口(如果构造函数需要三个参数,则会实现Function3接口)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接