簡體   English   中英

Scala工廠使用apply方法的泛型類型?

[英]Scala factory for generic types using the apply method?

假設我有以下特征來定義一個接口並采用幾個類型參數......

trait Foo[A, B] {

    // implementation details not important

}

我想使用伴侶對象作為特征的具體實現的工廠。 我還想強制用戶使用Foo接口而不是子類化所以我隱藏了伴隨對象中的具體實現,如下所示:

object Foo {

  def apply[A, B](thing: Thing): Foo[A, B] = {
    ???
  }

  private case class FooImpl[A1, B1](thing: Thing) extends Foo[A1, B1]

  private case class AnotherFooImpl[A2, B1](thing: Thing) extends Foo[A2, B1]

}

我希望能夠按如下方式使用工廠:

val foo = Foo[A1, B1](thing)  // should be an instance of FooImpl

val anotherFoo = Foo[A2, B1](thing)  // should be an instance of AnotherFooImpl

如何實現apply方法來實現這一目標? 這個SO帖子似乎接近標志。

怎么樣:

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)
}

現在:

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)
}

產量:

FooImpl(testing.X$Thing@4678c730)
AnotherFooImpl(testing.X$Thing@c038203)

使用TypeTags (為了克服類型參數的擦除),我們可以根據傳遞給apply方法的類型參數調用相應的隱藏實現,如下所示。 它正確地實例化了各自的實現,但是Foo的類型信息丟失了,實際上它會像_202那樣出現一些垃圾? 我不知道為什么會發生這種情況以及如何為Foo保留正確的類型。 也許有人可以對此有所了解。

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM