Explanation of singleton objects in Scala

后端 未结 4 458
Happy的楠姐
Happy的楠姐 2021-01-31 03:16

I get the coding in that you basically provide an \"object SomeClass\" and a \"class SomeClass\" and the companion class is the class declaration and the object is a singleton.

相关标签:
4条回答
  • 2021-01-31 03:23

    Yes, companion singletons provide an equivalent to Java's (and C++'s, c#'s, etc.) static methods.

    (indeed, companion object methods are exposed via "static forwarders" for the sake of Java interop)

    However, singletons go a fair way beyond this.

    • A singleton can inherit methods from other classes/traits, which can't be done with statics.
    • A singleton can be passed as a parameter (perhaps via an inherited interface)
    • A singleton can exist within the scope of a surrounding class or method, just as Java can have inner classes
    • It's also worth noting that a singleton doesn't have to be a companion, it's perfectly valid to define a singleton without also defining a companion class.

    Which helps make Scala a far more object-oriented language that Java (static methods don't belong to an object). Ironic, given that it's largely discussed in terms of its functional credentials.

    0 讨论(0)
  • 2021-01-31 03:24

    In many cases we need a singleton to stand for unique object in our software system. Think about the the solar system. We may have following classes

    class Planet
    object Earth extends Planet
    object Sun extends Planet
    

    object is a simple way to create singleton, of course it is usually used to create class level method, as static method in java

    0 讨论(0)
  • 2021-01-31 03:41

    Additional to the given answers (and going in the same general direction as jilen), objects play an important role in Scala's implicit mechanism, e.g. allowing type-class-like behavior (as known from Haskell):

    trait Monoid[T] {
      def zero:T
      def sum(t1:T, t2:T):T
    }
    
    def fold[T](ts:T*)(implicit m:Monoid[T]) = ts.foldLeft(m.zero)(m.sum(_,_))
    

    Now we have a fold-Function. which "collapses" a number of Ts together, as long as there is an appropriate Monoid (things that have a neutral element, and can be "added" somehow together) for T. In order to use this, we need only one instance of a Monoid for some type T, the perfect job for an object:

    implicit object StringMonoid extends Monoid[String] {
      def zero = ""
      def sum(s1:String, s2:String) = s1 + s2
    }
    

    Now this works:

    println(fold("a","bc","def"))  //--> abcdef
    

    So objects are very useful in their own right.

    But wait, there is more! Companion objects can also serve as a kind of "default configuration" when extending their companion class:

    trait Config {
      def databaseName:String
      def userName:String
      def password:String
    }
    
    object Config extends Config {
      def databaseName = "testDB"
      def userName = "scott"
      def password = "tiger"
    }
    

    So on the one hand you have the trait Config, which can be implemented by the user however she wants, but on the other hand there is a ready made object Config when you want to go with the default settings.

    0 讨论(0)
  • 2021-01-31 03:49

    Yes, it is basically a way of providing class methods when used as a companion object.

    0 讨论(0)
提交回复
热议问题