我几天来一直在研究隐式转换的问题,但不知怎的,我无法弄清楚我做错了什么。我阅读了有关涉及隐含的SO的所有其他问题,但我仍然不明白问题是什么。
作为一个例子,让我们考虑像这样的Java接口(为了简洁,T扩展了Object):
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())
)失败?这应该是第一个知道实际类型的EntityType和DTOType的地方,对吗?
3)有没有更好的方法来实现我想要实现的目标?再一次,这不是我想要做的实际事情,但足够接近。
如果这个问题无知,请提前道歉,并提前感谢您的帮助。
答案 0 :(得分: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
来自{{1}转到DTOType
,但您实际上只有Java接口所需的EntityType
到EntityType
转换。
编辑:例如,这是您使用标准隐式转换发布的工作版本:
EntityType
注意哪些类型在哪里使用! (谁需要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
以及您需要转换哪个方向?)