2017-06-07 64 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