How to create object/singleton of generic type in Scala?

后端 未结 3 1525
夕颜
夕颜 2021-02-10 23:42

In the code shown below, how can I convert EmptyTree to object (Singleton) ?

trait Tree[T] {
    def contains(num: T): Boolean
    def inc( num: T )         


        
相关标签:
3条回答
  • 2021-02-10 23:45

    You have to fix the generic argument because that's the only time you can provide it:

    scala> trait A[T]
    defined trait A
    
    scala> object B extends A[Int]
    defined object B
    

    Obviously you want to reuse EmptyTree for all types of T, so instead of defining A[SOMETYPE] for each type just use bottom type Nothing:

    scala> object B extends A[Nothing]
    defined object B
    

    This object can be used with any tree.

    That's exactly how Option[T] is implemented in Scala. Here is how None is defined:

    case object None extends Option[Nothing]
    
    0 讨论(0)
  • 2021-02-10 23:51

    If keeping generics, also there is an option to add empty factory - like it's done for Map and Vector. Off course, with such an implementation it will not be a unique instance object for every creation, but when using inc method, it will not produce new objects, it will just reference itself.

    object DataTree {
      def empty[T <% Ordered[T]] = new Tree[T] {
          def contains(num: T):Boolean = false
          def inc(num: T): Tree[T] = {
            new DataTree(num, this, this)
          }
          override def toString = "."
      }
    }
    

    So you can instantiate it as following:

    val t = new DataTree(20, DataTree.empty[Int], DataTree.empty[Int])
    
    0 讨论(0)
  • 2021-02-10 23:58

    Let me detalize Alexey's answer. Here is full implementation with some code style improvements:

    First define your trait with aknowledgment of its covariance:

     trait Tree[+T] {
        def contains[U >: T : Ordering](num: U): Boolean
    
        def inc[U >: T : Ordering](num: U): Tree[U]
      }
    

    Next define your subtype-of-all-trees object

      case object EmptyTree extends Tree[Nothing] {
        def contains[U >: Nothing : Ordering](num: U): Boolean = false
        def inc[U >: Nothing : Ordering](num: U): Tree[U] =
          DataTree(num, EmptyTree, EmptyTree)
        override def toString = "."
      }
    

    Now change your general case implementation:

      case class DataTree[T: Ordering](x: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
        import Ordering.Implicits._
        def contains[U >: T : Ordering](num: U): Boolean = 
          if (num < x) left.contains(x)
          else if (num > x) right.contains(x)
          else true
    
        def inc[U >: T : Ordering](num: U): Tree[U] = 
          if (num < x) DataTree(x, left.inc(num), right)
          else if (num > x) DataTree(x, left, right.inc(num))
          else this
    
        override def toString = "{" + left + x + right + "}"
      }
    

    You could be a little bit frustrated since I replaced your Ordered with Ordering, but you should know that view bounds are deprecated

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