带类型参数的Scala方法

时间:2017-06-07 12:54:55

标签: scala

这是我的情况:

trait BPO
trait BBO
class PointBO extends BBO
class PointPO extends BPO
class CircleBO extends BBO
class CirclePO extends BPO

trait Mapper[-P <: BPO,+B <: BBO] {
  def mapAsBBO(bpo: P): B
}

class PointMapper extends Mapper[PointPO,PointBO]{
  override def mapAsBBO(bpo: PointPO): PointBO = {
    println("Construct point")
    new PointBO
  }
}

class CircleMapper extends Mapper[CirclePO,CircleBO] {
  override def mapAsBBO(bpo: CirclePO): CircleBO = {
    println("Construct circle")
    new CircleBO
  }
}

class Registry{
  def method[P,B](po:P,bo:B)(implicit mapper: Mapper[P,B]) = mapper.mapAsBBO(po)
}

val r = new Registry
val s = r.method[PointPO,PointBO](new PointPO,new PointBO)

我想传递给方法method,只是涉及映射的两个类,让Scala类型推断为我实现正确的映射器,是否可能?

我收到此错误:

错误:(31,40)找不到参数映射器的隐含值:A $ A191.this.Mapper [A $ A191.this.PointPO,A $ A191.this.PointBO] lazy val s = r.method [PointPO,PointBO](新PointPO,新PointBO)                                       ^

对我来说另一种方式应该没问题,将其称为方法method只传递mapper类:

val s = r.method[PointMapper](new PointPO,new PointBO)

这是完成这条街之一的任何方式,如果其中一条比另一条更好,还有一点解释。

修改

在原点我想制作具有两个参数协变的特征Mapper:

trait Mapper[+P <: BPO,+B <: BBO] {
  def mapAsBBO(bpo: P): B
}

就像下面的任务一样:

val d:Mapper[BPO,BBO] = new CircleMapper()

但编译器抱怨我必须是conovariant的P参数

还有另一种解决方案吗?

问候。

1 个答案:

答案 0 :(得分:1)

首先,在您的代码中,隐式映射器丢失(如异常中所述)。

所以我在下面添加了这些内容。 除此之外,如果您为映射器添加隐式值,则会出现类型边界问题,因为该方法需要与Mapper相同的类型边界,因此我也对此进行了调整:

trait BPO
trait BBO
class PointBO extends BBO
class PointPO extends BPO
class CircleBO extends BBO
class CirclePO extends BPO

trait Mapper[P <: BPO,B <: BBO] {
  def mapAsBBO(bpo: P): B
}

class PointMapper extends Mapper[PointPO,PointBO]{
  override def mapAsBBO(bpo: PointPO): PointBO = {
    println("Construct point")
    new PointBO
  }
}

class CircleMapper extends Mapper[CirclePO,CircleBO] {
  override def mapAsBBO(bpo: CirclePO): CircleBO = {
    println("Construct circle")
    new CircleBO
  }
}

class Registry{
  def method[P <: BPO,B <: BBO](po:P,bo:B)(implicit mapper: Mapper[P,B]) = mapper.mapAsBBO(po)
}

implicit val pMapper = new PointMapper()
implicit val cMapper = new CircleMapper()

val r = new Registry
r.method(new PointPO,new PointBO)

修改

r.method中删除了显式类型参数,因为它们是由编译器推断的。还删除了与Mapper类型参数的共同和反向差异,因为对于此功能,它不是必需的,并且没有给出关于它被使用的原因的进一步上下文,因此它只会导致混淆。

EDIT2

如果你没有理由实例化mapper类,你也可以将它们定义为隐式对象:

trait BPO
trait BBO
class PointBO extends BBO
class PointPO extends BPO
class CircleBO extends BBO
class CirclePO extends BPO

trait Mapper[P <: BPO,B <: BBO] {
  def mapAsBBO(bpo: P): B
}

implicit object PointMapper extends Mapper[PointPO,PointBO]{
  override def mapAsBBO(bpo: PointPO): PointBO = {
    println("Construct point")
    new PointBO
  }
}

implicit object CircleMapper extends Mapper[CirclePO,CircleBO] {
  override def mapAsBBO(bpo: CirclePO): CircleBO = {
    println("Construct circle")
    new CircleBO
  }
}

class Registry{
  def method[P <: BPO,B <: BBO](po:P,bo:B)(implicit mapper: Mapper[P,B]) = mapper.mapAsBBO(po)
}

val r = new Registry
r.method(new PointPO,new PointBO)