2017-06-07 63 views
1

这是我的情况: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] 懒VAL S = r.method [PointPO,PointBO](新PointPO,新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参数

有另一种解决方案来做到这一点?

问候。

+0

您就协方差的第二个问题,看看这里:HTTPS:/ /stackoverflow.com/questions/9619121/why-is-parameter-in-contravariant-position – thwiegan

回答

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类型参数中删除了co-和contra-variance,因为对于这个功能它是不需要的,并且没有给出关于它为什么被使用的更多的上下文,所以它只会导致混淆。

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) 
+0

这绝对是真的。 – Giorgio