gpt4 book ai didi

scala - Scala中Anonymous,Singleton和Companion对象之间的差异

转载 作者:行者123 更新时间:2023-12-04 17:43:35 25 4
gpt4 key购买 nike

我在Google上进行了搜索,以查找并了解对Scala中Anonymous,Singleton和Companion对象之间差异的深入了解

我发现在斯卡拉,

  • 没有引用名称的对象称为匿名对象。当您不想进一步重用匿名对象时,最好创建匿名对象。
  • Singleton对象是通过使用object关键字而不是通过类声明的对象。调用单例对象内部声明的方法不需要对象,也没有静态概念。因此,scala创建了一个singleton对象,为我们的程序执行提供了入口点。
  • 在scala中,当您有一个与单例对象同名的类时,它称为伴随类,而单例对象则称为伴随对象。伴随类及其伴随对象都必须在同一源文件中定义。

  • 那么,如果我们不想重用,为什么匿名对象很好呢? Singleton非常简单易懂,但是Companion Object的真正目的是什么?我的意思是编写同伴类和同伴对象都必须在同一个源文件中定义的规则背后的故事是什么?我们拥有与Singleton对象同名的类是Companion Object的唯一原因吗?

    我猜应该在Scala中使用这些功能有一些重要的原因。有什么解释?是否有资源可以从中学习更多有关Scala对象的信息?

    最佳答案

    这是一个很长的答案,但我希望它能澄清一些潜在的使用场景。

    So, why Anonymous object is good if we don't want to reuse?



    我认为,与其他两个术语不同,“匿名对象”一词在Scala世界中定义不明确。我可以想到几件事:
  • 您没有分配给任何命名变量或字段的某些对象。在几种情况下可能会发生这种情况。例如,考虑某些集合上的foldLeft。您想在此处传递初始值,但是通常不需要给它起任何名字,因为这是一个可抛弃的对象。另一种情况是,当此类对象包含您要使用的某种逻辑(一种strategy pattern)时。考虑遵循标准ParIterableLike
  • 的内容

      def count(p: T => Boolean): Int = {
    tasksupport.executeAndWaitResult(new Count(p, splitter))
    }

    此特定实现使用命名方法 tasksupport,因为它希望它是可自定义的。但是,如果不是那样,那可能就像
      def count(p: T => Boolean): Int = {
    new ExecutionContextTaskSupport.executeAndWaitResult(new Count(p, splitter))
    }

    new ExecutionContextTaskSupport将是一个匿名对象。
  • 应该称为“匿名类型对象”的东西。
  • 如果为某个type-classes实现了证据,这种情况就会经常发生。考虑Play-Json
  • 中的此示例

    case class Resident(name: String, age: Int, role: Option[String])

    import play.api.libs.json._
    implicit val residentReads = Json.reads[Resident]

    // In a request, a JsValue is likely to come from `request.body.asJson`
    // or just `request.body` if using the `Action(parse.json)` body parser
    val jsonString: JsValue = Json.parse(
    """{
    "name" : "Fiver",
    "age" : 4
    }"""
    )

    val residentFromJson: JsResult[Resident] = Json.fromJson[Resident](jsonString)

    在这里, residentReads的对象和类将由 Json.reads后面的宏生成,并且您不必关心它具有什么类型,只要它实现 Reads特性即可。
  • 或者您是否有依赖于返回的某些策略的模板方法。也就是说,在这些情况下,所有调用者都需要知道的类型是它与某些指定的接口(interface)协定匹配(即扩展了某些trait)。考虑一下ExecutionContextImpl
  • 中的这一部分

      def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter):
    ExecutionContextImpl with ExecutionContextExecutorService = {
    new ExecutionContextImpl(Option(es).getOrElse(createDefaultExecutorService(reporter)), reporter)
    with ExecutionContextExecutorService {
    final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService]
    override def execute(command: Runnable) = executor.execute(command)
    override def shutdown() { asExecutorService.shutdown() }
    override def shutdownNow() = asExecutorService.shutdownNow()
    override def isShutdown = asExecutorService.isShutdown
    override def isTerminated = asExecutorService.isTerminated
    override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit)
    override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable)
    override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t)
    override def submit(runnable: Runnable) = asExecutorService.submit(runnable)
    override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables)
    override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit)
    override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables)
    override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit)
    }
    }

    同样,只要满足 ExecutionContextExecutorService的约定,调用方就不必关心特定的类型,尤其是我们不在乎它是基于 ExecutionContextImpl而不是任何其他实现的。

    实际上,如果您需要将某件作品传递到某处,由于某种原因,该作品由于某些原因不适合简单的 Function接口(interface)(或者因为它需要更多),那么通常将案例1和案例2(即“匿名类型的匿名对象”)结合在一起而不是一种生命周期方法或出于历史兼容性的原因)。最典型的例子是 java.lang.Runnable。这是 ExecutionContextImpl的另一个示例:
    // As per ThreadFactory contract newThread should return `null` if cannot create new thread.
    def newThread(runnable: Runnable): Thread =
    if (reserveThread())
    wire(new Thread(new Runnable {
    // We have to decrement the current thread count when the thread exits
    override def run() = try runnable.run() finally deregisterThread()
    })) else null
    Thread类需要 Runnable作为执行的工作,我们想将作为参数获取的 runnable包装到另一个参数,该参数最后将调用 deregisterThread,但我们不在乎对象的名称或其名称。实际类型。

    what's the real purpose of Companion Object?



    我可以想到使用伴侣对象的几个主要原因。
  • 在Java世界中,应该是static方法或static字段。例如,假设您编写了自定义任意精度算术BigInt。您会将著名的常量(例如zero)放在哪里,以便可以从外部访问它们?伴随对象就是答案。这种伴随对象的另一种非常典型的用法是提供一些工厂方法的方法(通常通过apply),因此例如,您可以编写

  •  List.empty
    List(1, 2, 3)

    没有 new关键字
  • 您有一些类,并且想要为其提供一些共享的默认实例。创建一个更多的该类实例就可以了,就不必单例了。例如scala.util.Random将类和伴随对象都定义为

  • object Random extends Random

    所以你可以做
    Random.nextInt
  • 可能最应有的东西可能被称为“伴侣对象”。您有一些类的层次结构,并且应该将逻辑绑定(bind)到层次结构中的每个类,但这些逻辑不是层次结构中类的类型。这听起来可能有点复杂,但并不难。 scala.concurrent包大量采用了这种想法。考虑例如:

  • abstract class GenTraversableFactory[CC[X] <: GenTraversable[X] with GenericTraversableTemplate[X, CC]]
    extends GenericCompanion[CC] {

    private[this] val ReusableCBFInstance: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] {
    override def apply() = newBuilder[Nothing]
    }
    def ReusableCBF: GenericCanBuildFrom[Nothing] = ReusableCBFInstance

    // some other stuff

    }

    List随播对象实现了几层到继承树的层次
    object List extends SeqFactory[List] {
    /** $genericCanBuildFromInfo */
    implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] =
    ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]

    def newBuilder[A]: Builder[A, List[A]] = new ListBuffer[A]

    // some other stuff

    }

    实际上,许多收集方法都使用此 canBuildFrom,将它们转换为其他集合,例如 ++map。而且,这个巧妙的技巧使您可以通过映射到其他集合类型来编写类似的代码:

    val list: List[Int] = Vector(1, 2, 3).map(x => 2 * x)(breakout)

    关于scala - Scala中Anonymous,Singleton和Companion对象之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47856851/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com