我在Google中搜索并了解深入了解Scala中Anonymous,Singleton和Companion Object之间的差异
我发现在scala中,
-
没有引用名称的对象称为匿名对象 . 当您不想进一步重用它时,最好创建匿名对象 .
-
Singleton对象是一个使用object关键字而不是类声明的对象 . 调用在singleton对象中声明的方法并不需要任何对象,也没有静态概念 . 因此scala创建了一个单例对象,为程序执行提供入口点 .
-
在scala中,当你有一个与singleton对象同名的类时,它被称为伴随类,而singleton对象被称为companion对象 . 伴随类及其伴随对象都必须在同一源文件中定义 .
那么,如果我们不想重用,为什么Anonymous对象是好的呢? Singleton很容易理解,但Companion Object的真正目的是什么?我的意思是编写伴侣类和伴随对象的规则背后的故事都必须在同一个源文件中定义? Companion Object的唯一原因是我们有一个与singleton对象同名的类吗?
我想Scala中的这些功能应该有一些重要的原因 . 有什么解释或是否有资源可以从中了解有关Scala对象的更多信息?
2 回答
这是一个很长的答案,但我希望它澄清了一些潜在的使用场景 .
我认为,与其他两个不同,“匿名对象”这个术语在Scala世界中没有明确定义 . 我可以想到一些可能被称为的事情:
foldLeft
. 您希望在那里传递初始值,但通常不需要给它任何名称,因为这是一次性对象 . 另一种情况是这样的对象包含你想要使用的一些逻辑(一种strategy pattern) . 考虑以下来自标准ParIterableLike
的文章此特定实现使用命名方法
tasksupport
,因为它希望它可以自定义 . 但如果不是这样,它可能就像是和
new ExecutionContextTaskSupport
将是一个匿名对象 .应该被称为“匿名 type 对象”的东西 .
如果你为一些type-classes实施证据,这种情况经常发生 . 从Play-Json开始考虑这个例子
这里
residentReads
的对象和类将由Json.reads
后面的宏生成,只要它实现了Reads
特性,你就不关心它的类型 .trait
)的情况 . 从ExecutionContextImpl
开始考虑这件作品只要符合
ExecutionContextExecutorService
的 Contract ,调用者就不会关心特定类型,特别是我们并不关心它是基于ExecutionContextImpl
而不是任何其他实现 .实际情况#1和#2(即“匿名类型的匿名对象”)经常被合并,如果你需要传递一些工作,由于某些原因不适合简单的接口(因为它需要更多)比一个生命周期方法或历史兼容性原因) . 最好的例子是
java.lang.Runnable
. 这是ExecutionContextImpl
的另一个例子:Thread
类需要Runnable
作为要执行的工作,我们想要包装runnable
作为参数与另一个将在最后调用deregisterThread
的参数,但我们不关心对象的名称或其实际类型 .我可以想到使用Companion Objects的几个主要原因 .
static
方法或static
字段 . 例如,假设您为自己编写了自定义精度算术BigInt
. 你会在哪里放置众所周知的常量,如zero
,以便从外面访问它们?伴侣对象就是答案 . 这种伴随对象的另一个非常典型的用法是提供一些工厂方法的方法(通常通过apply
),例如你可以写没有
new
关键字scala.util.Random
将类和伴随对象定义为所以你可以做到
scala.concurrent
包非常采用这个想法 . 考虑例如:List
伴侣对象实现了几个级别到继承树这个
canBuildFrom
实际上被许多集合方法使用,这些集合方法将它们转换为其他集合,例如++
或map
. 此外,这个聪明的技巧允许您通过映射到其他集合类型来编写类似的东西:因为我们不需要关心为其分配名称 . 考虑像
List("a","b","c")
这样的列表的定义 . 在这里,我们使用3个匿名对象创建它 . 我们也可以这样做:显然,前一种选择更方便使用 .
基本上它保留了不属于具有相同名称的特定类的实例的静态方法 . 伴随对象通常出现在scala集合中,例如可以轻松创建对象 . 考虑使用
List("a", "b", "c")
的相同示例 . List实际上是一个抽象类,因此它不能简单地以这种方式创建:(为什么? - 但这是另一个问题)而且List("a","b","c")无论如何都是较短的形式 . 因此,为了使用该较短的形式,在伴随对象List中引入了方法
override def apply[A](xs: A*): List[A]
. 希望现在应该清楚为什么伴侣对象是有用的 .这是一个解释伴随对象的好处的资源:http://daily-scala.blogspot.com/2009/09/companion-object.html