2012-05-11 47 views
1

我一直在与天隐式转换的问题了,但不知何故,我无法找出我做错了通用的特质隐式转换。我读过所有其他关于隐含问题的问题,但我仍然不明白问题所在。斯卡拉上实现Java接口

举个例子,让我们考虑这样一个Java接口(T扩展对象为简洁起见):

public interface JPersistable<T extends Object> { 
    public T persist(T entity); 
} 

在Scala中,我做到以下几点:

case class A() 
case class B() extends A 
case class C() 
case class D() extends C 

trait Persistable[DTOType <: A, EntityType <: C] { 
    // this would be implemented somewhere else 
    private def doPersist(source: EntityType): EntityType = source 

    // this does not implement the method from the Java interface 
    private def realPersist(source: DTOType)(implicit view: DTOType => EntityType): EntityType = doPersist(source) 

    // this DOES implement the method from the Java interface, however it throws: 
    // error: No implicit view available from DTOType => EntityType. 
    def persist(source: DTOType): EntityType = realPersist(source) 
} 

case class Persister() extends Persistable[B, D] with JPersistable[B] 

object Mappings { 
    implicit def BToD(source: B): D = D() 
} 

object Test { 
    def main(args: Array[String]) { 

    import Mappings._ 
    val persisted = Persister().persist(B()) 
    } 
} 

正如评论指出,我在编译时得到一个异常。我想我的问题是:

1)为什么我需要指定的doRealPersist明确的隐式转换?即使我做了以下操作,我预计转换也会发生:

trait Persistable[DTOType <: A, EntityType <: C] { 
    // this would be implemented somewhere else 
    private def doPersist(source: EntityType): EntityType = source 

    def persist(source: DTOType): EntityType = doPersist(source) 
} 

但是,这也不能编译。

2)为什么在persist编译失败,而不是实际的方法调用(val persisted = Persister().persist(B()))?这应该是实际类型的实体类型和DTOType已知的第一个地方,对吗?

3)是否有更好的方式做什么,我想达到什么目的?再次,这不是我想要做的实际事情,但足够接近。

道歉提前,如果这个问题是无知和感谢很多提前对您有所帮助。

回答

2

您需要进行转换提供性状内。你不能从外面传递它,因为外部不知道persist暗中需要realPersist这需要隐式转换。即使没有考虑JPersistable,这一切都会失败。

例如,您可以添加

implicit def view: DTOType => EntityType 

如性状的方法,然后它会编译。 (您可以删除realPersist然后也。)

然后,你需要一种方式来获得该视图集。你可以

case class Persister()(implicit val view: B => D) extends Persistable[B,D] 

然后你都很好。 (该implicit val满足性状的implicit def

但现在你有更大的问题:你的Java接口的签名不符合您的Scala签名。等效Scala是

trait JPersistable[T <: Object] { def persist(t: T): T } 

了解如何persist需要并返回相同的类型?并看看它在你的Scala类中如何不是?这不可行,也不应该!所以你必须重新考虑你想要在这里完成的事情。也许你只是想让隐式转换可用 - 不能传递给方法! - 并让Scala为您应用隐式转换,以便您认为自己有一个persist,该映射从DTOTypeEntityType映射,但是您确实只需要转换Java接口所需的EntityTypeEntityType


编辑:例如,这里就是你贴只是使用标准的隐式转换的一个工作版本:

trait JPer[T] { def persist(t: T): T } 
class A 
case class B() extends A 
class C 
case class D() extends C 
trait Per[Y <: C] extends JPer[Y] { 
    private def doIt(y: Y): Y = y 
    def persist(y: Y) = doIt(y) 
} 
case class Perer() extends Per[D] // "with JPer" wouldn't add anything! 
object Maps { implicit def BtoD(b: B): D = D() } 
object Test extends App { 
    import Maps._ 
    val persisted = Perer().persist(B()) 
} 

注重类型使用哪些地方! (谁需要B和谁需要D和哪个方向是否需要转换?)

+0

感谢您的快速解答Rex。仍然让我困惑的是,对于Predef implicits(如'byte2short'),如果您想使用转换,则不必指定抽象def。我预计转换将可用......好吧,含蓄地。特别是在我的问题1中,我希望scala一旦知道类型就能解决转换。至少我会期待如果我在你的例子中将'Mappings._'带入'Persister'的范围,我不必再次实现隐式def。 它对我来说仍然有点神秘我究竟是在做什么错... – LeChe

+0

@LeChe - 我已经更新了我的答案,显示了一个使用“让外部隐式转换做它”的建议。 –

+0

当然,我是一个白痴!为什么特质需要知道A树,转换应该完全透明!该死,我现在觉得很愚蠢。非常感谢你的解释。 – LeChe