38

当您创建一个案例类时,编译器会创建一个相应的伴随对象,其中包含一些案例类的好东西:一个apply与主构造函数匹配的工厂方法equals、、、hashCodecopy

有点奇怪,这个生成的对象扩展了 FunctionN。

scala> case class A(a: Int)                                 
defined class A

scala> A: (Int => A)
res0: (Int) => A = <function1>

只有在以下情况下才会出现这种情况:

  • 没有手动定义的伴随对象
  • 只有一个参数列表
  • 没有类型参数
  • 案例类不是抽象的。

好像是两年前添加的。最新的化身就在这里

有没有人使用它,或者知道为什么添加它?它使用静态转发器方法稍微增加了生成的字节码的大小,并显示在#toString()伴随对象的方法中:

scala> case class A()
defined class A

scala> A.toString
res12: java.lang.String = <function0>

更新

使用单一apply方法手动创建的对象不会自动被视为FunctionN

object HasApply {
  def apply(a: Int) = 1
}
val i = HasApply(1)

// fails
//  HasApply: (Int => Int) 
4

4 回答 4

48

案例类伴生对象实现FunctionN的原因是,之前案例类生成的是类和工厂方法,而不是伴生对象。当我们向 Scala 添加提取器时,将工厂方法转换为具有应用和取消应用方法的完整伴生对象会更有意义。但是,由于工厂方法确实符合 FunctionN,所以伴随对象也需要符合。

[编辑] 也就是说,将伴随对象显示为自己的名称而不是“功能”是有意义的

于 2010-06-16T14:25:59.720 回答
11

除了 oxbow_lakes 关于它的自然性的回复之外,将构造函数用作一等函数通常很有用,特别是与 Scala 集合高阶函数结合使用。对于(一个微不足道的)示例,

scala> case class Foo(i : Int)
defined class Foo

scala> List(1, 2, 3) map Foo   
res0: List[Foo] = List(Foo(1), Foo(2), Foo(3))
于 2010-06-16T09:37:57.503 回答
11

好吧,鉴于target.apply(a1, a2, a3 ... aN)在 Scala 中:

  1. 可以加糖target(a1, a2, a3 ... aN)
  2. 是需要实现的方法FunctionN

伴随对象似乎很自然:

object MyClass {
  def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}

是真的:

object MyClass extends FunctionN[A1, ... , AN, MyClass]{
  def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}

所以添加对我来说似乎很自然(我不确定为什么它对你来说似乎“奇怪”?)。至于它是否真的添加了什么;好吧,那是给比我聪明的人的!

于 2010-06-15T22:38:06.100 回答
5
Welcome to Scala version 2.8.0.RC3 (Java HotSpot(TM) Client VM, Java 1.6.0_20).

scala> case class CC3(i: Int, b: Boolean, s: String)
defined class CC3

scala> CC3
res0: CC3.type = <function3>

scala> CC3.apply(1, true, "boo!")
res1: CC3 = CC3(1,true,boo!)

scala> CC3(1, true, "boo!")
res2: CC3 = CC3(1,true,boo!)
于 2010-06-15T22:19:08.830 回答