为什么案例类伴生对象要扩展 FunctionN?

发布于 2024-09-05 15:47:32 字数 1198 浏览 9 评论 0 原文

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

有点奇怪的是,这个生成的对象扩展了 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>

UPDATE

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

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

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

When you create a case class, the compiler creates a corresponding companion object with a few of the case class goodies: an apply factory method matching the primary constructor, equals, hashCode, and copy.

Somewhat oddly, this generated object extends FunctionN.

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

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

This is only the case if:

  • There is no manually defined companion object
  • There is exactly one parameter list
  • There are no type arguments
  • The case class isn't abstract.

Seems like this was added about two years ago. The latest incarnation is here.

Does anyone use this, or know why it was added? It increases the size of the generated bytecode a little with static forwarder methods, and shows up in the #toString() method of the companion objects:

scala> case class A()
defined class A

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

UPDATE

Manually created objects with a single apply method are not automatically considered as FunctionN:

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

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

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

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

发布评论

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

评论(4

只想待在家 2024-09-12 15:47:32

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

[编辑] 也就是说,让伴生对象显示为它们自己的名称而不是“函数”是有意义的

The reason why case class companion objects implement FunctionN is that before, case classes generated a class and a factory method, not a companion object. When we added extractors to Scala it made more sense to turn the factory method into a full companion object with apply and unapply methods. But then, since the factory method did conform to FunctionN, the companion object needed to conform, too.

[Edit] That said, it would make sense to have companion objects show as their own name, not as "function"

酒废 2024-09-12 15:47:32

好吧,考虑到 Scala 中的 target.apply(a1, a2, a3 ... aN)

  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)
}

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

Well, given that target.apply(a1, a2, a3 ... aN) in Scala:

  1. can be sugared by target(a1, a2, a3 ... aN)
  2. is the method which needs to be implemented by FunctionN

it seems natural that a companion object:

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

is really:

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

So the addition seems to be natural to me (I'm not sure why it seems "odd" to you?). As to whether it actually added anything; well, that is for someone smarter than me!

太阳男子 2024-09-12 15:47:32

除了 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))

Aside from oxbow_lakes's reply about the naturalness of it, it can often be useful to have constructors available as first-class functions, particularly in conjunction with Scala collections higher-order functions. For (a trivial) example,

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))
暖树树初阳… 2024-09-12 15:47:32
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!)
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!)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文