【问题标题】:Scala method with type parameter具有类型参数的 Scala 方法
【发布时间】:2017-06-07 12:54:55
【问题描述】:

这是我的情况:

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](new PointPO,new PointBO) ^

另一种方法对我来说应该没问题,称为方法method,只传递映射器类:

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

这是完成这条街道之一的任何方法吗?如果其中一个比另一个更好,再加上一点解释。

编辑:

最初我想用两个参数协变来制作特征映射器:

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

这样就可以了下面的任务:

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

但是编译器向我抱怨 P 参数必须是逆变的

有替代解决方案吗?

问候。

【问题讨论】:

标签: scala


【解决方案1】:

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

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

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

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

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)

【讨论】:

  • 确实如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-22
  • 2019-01-19
  • 2018-10-24
  • 2021-04-20
  • 2022-01-01
  • 1970-01-01
相关资源
最近更新 更多