使用带有工厂函数的抽象类型参数来生成正确类型的新对象

时间:2016-09-04 07:30:31

标签: scala

我有一个抽象类,将以多种不同的方式实现。我正在尝试创建一个方法,可以将这些实现中的任何一个作为参数,并返回相同类型的新实例。我试图通过传递"工厂"来实现这种行为。函数到产生抽象类型的新对象的方法(将在每个实现者中适当地设置)。

我试图将我遇到的问题分解为以下代码:

我的父抽象类:

abstract class Parent(val x: Int) {
  type Self <: Parent

  def factory: Int ⇒ Self

  def me = "Parent"
}

Child类的一个示例:

class Child(x: Int) extends Parent(x) {
  type Self = Child

  override def factory: Int ⇒ Self = {
    (v: Int) ⇒ new Child(v)
  }

  override def me = "Child"
}

我尝试使用Self类型参数来确保factory方法生成正确类型的对象。

现在方法本身:

object Parent {
  def transform[T <: Parent](input: T#Self, factory: (Int ⇒ T#Self)): T#Self = {
    //do stuff with input
    input.me
    val result = 123
    factory(result)
  }
}

现在,当我尝试实际连线时:

class Transformer[T <: Parent] {

  var everyone: List[T#Self] = List.empty

  def start() = {
    val updated = for (e ← everyone) yield {
      Parent.transform[T](e, e.factory)
    }

    everyone = updated
  }
}

当我尝试将工厂传递给transform方法

时出现编译错误

Type mismatch, expected (Int) => T#Self, actual (Int) => Parent.this.Self

我尝试了各种各样的方法来实现这一点,但没有运气。我对此仍然很陌生,所以我可能(很可能)尝试在这里做一些疯狂的事情。一个更好的选择将非常感激,但我仍然有兴趣看看是否有可能让这样的东西工作。最终目标是让transform方法生成与参数提供的完全相同类型的新实例。

非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

  

我试图使用Self类型参数来确保   factory方法生成一个正确类型的对象。

这让我想起了tpolecat的Returning the "Current" Type in Scala

  

我有一个类型层次结构...如何声明一个返回“当前”类型的超类型方法?

我们可以将该帖子中讨论的F-Bounded Types方法调整为ParentChild层次结构:

trait Parent[A <: Parent[A]] { this: A =>

  def x: Int

  def factory: Int ⇒ A

  def me = "Parent"
}

class Child(override val x: Int) extends Parent[Child] {

  override def factory = (v: Int) ⇒ new Child(v)

  override def me = "Child"
}

class OtherChild(override val x: Int) extends Parent[OtherChild] {

  override def factory = (v: Int) ⇒ new OtherChild(v)

  override def me = "OtherChild"
}

object Parent {
  def transform[A <: Parent[A]](input: A): A = {
    //do stuff with input
    input.me
    val result = 123
    input.factory(result)
  }
}

然后,在Bonus Round: How do we deal with collections?部分之后,您的Transformer会变成这样:

class Transformer {

  import scala.language.existentials

  var everyone = List[A forSome { type A <: Parent[A] }](new Child(1), new OtherChild(2))

  def start() = {
    val updated = everyone.map(Parent.transform(_))

    everyone = updated
  }
}