Scala factory for generic types using the apply method?

前端 未结 2 1918
春和景丽
春和景丽 2021-02-06 10:36

Suppose that I have the following trait that defines an interface and takes a couple of type parameters...

trait Foo[A, B] {

    // implementation details not i         


        
相关标签:
2条回答
  • 2021-02-06 11:25

    How about:

    trait Foo[A, B]
    trait Factory[A, B] {
      def make(thing: Thing): Foo[A, B]
    }
    
    class Thing
    
    object Foo {
    def apply[A, B](thing: Thing)(implicit ev: Factory[A, B]) = ev.make(thing)
    
    private case class FooImpl[A, B](thing: Thing) extends Foo[A, B]
    private case class AnotherFooImpl[A, B](thing: Thing) extends Foo[A, B]
    
    implicit val fooImplFactory: Factory[Int, String] = new Factory[Int, String] {
      override def make(thing: Thing): Foo[Int, String] = new FooImpl[Int, String](thing)
    }
    
    implicit val anotherFooImplFactory: Factory[String, String] = new Factory[String, String] {
      override def make(thing: Thing): Foo[String, String] = new AnotherFooImpl[String, String](thing)
    }
    

    And now:

    def main(args: Array[String]): Unit = {
      import Foo._
    
      val fooImpl = Foo[Int, String](new Thing)
      val anotherFooImpl = Foo[String, String](new Thing)
    
      println(fooImpl)
      println(anotherFooImpl)
    }
    

    Yields:

    FooImpl(testing.X$Thing@4678c730)
    AnotherFooImpl(testing.X$Thing@c038203)
    
    0 讨论(0)
  • 2021-02-06 11:27

    Using TypeTags (to overcome erasure of type parameters), we can call the respective hidden implementations based on the type parameters passed in to the apply method like below. It correctly instantiates the respective implementations but the type information for Foo is lost, in fact its coming some garbage like _202 etc? I don't know why that is happening and how to retain the correct types for Foo. Maybe someone can throw light on this.

    trait Foo[A,B]
    object Foo {
       def apply[A: TypeTag, B: TypeTag](thing: Thing) = 
        if(typeTag[A] == typeTag[Int])  
          FooImpl(thing) 
        else if(typeTag[A] == typeTag[String]) 
          AnotherFooImpl(thing) 
        else 
          new Foo[Double,Double] {}
    
       private case class FooImpl(thing: Thing) extends Foo[Int, String]
       private case class AnotherFooImpl(thing: Thing) extends Foo[String, String]
      } 
    
    Foo[Int,String](new Thing) // Foo[_202, _203] = FooImpl($sess.cmd123$Thing@50350b75)
    
    The actual types for _203 and _203 are: ???
    // type _203 >: String with _201, type _202 >: Int with _200 
    
    
    Foo[String,String](new Thing) //Foo[_202, _203] = AnotherFooImpl($sess.cmd123$Thing@51d80d6)
    
    0 讨论(0)
提交回复
热议问题