scala – 如何从泛型函数返回正确的类型传递了相关的抽象类型参
我正在尝试为以下情况编写“更好”(更惯用?)
Scala代码:
我有一组类,这些类将由属于一组并行的引用案例类的引用字段标识,如下所示: abstract sealed class Ref(value: String) case class ARef(value: String) extends Ref(value) case class BRef(value: String) extends Ref(value) case class CRef(value: String) extends Ref(value) trait Referenced { type refType <: Ref val ref: refType } trait A extends Referenced { type refType = ARef } trait B extends Referenced { type refType = BRef } trait C extends Referenced { type refType = CRef } 另一个类(可能会变成State monad的状态类型)将包含这些类型的列表,并提供一个函数来检索一个对象,给出它的引用.我希望这个返回值适当地输入,即给定 val aRef = ARef("my A ref") 我希望能够打个电话: val myA: Option[A] = context.get[A](aRef) 并确保取回选项[A],而不仅仅是选项[参考].到目前为止,我实现这一目标的最佳尝试类似于以下内容: trait Context { // ... other stuff ... protected val aList: List[A] protected val bList: List[B] protected val cList: List[C] def get[R <: Referenced](ref: R#refType): Option[R] = { val result = ref match { case aRef: ARef => aList.find(_.ref == aRef) case bRef: BRef => bList.find(_.ref == bRef) case cRef: CRef => cList.find(_.ref == cRef) case _ => throw new RuntimeException("Unknown Ref type for retrieval: "+ref) } result.asInstanceOf[Option[R]] } } 这似乎工作正常,但有一个臭“asInstanceOf”调用它.我有兴趣看到如何更好地完成这项工作的想法(并检查我是否已经错过了一个明显更简单的解决方案). 请注意,由于其他原因,我到目前为止选择使用抽象类型而不是参数类型(特征A扩展了Referenced [ARef]样式),但如果原因足够引人注意,可能会改变它. 解决方法
在这种情况下,没有铸造所需的机器真的不是那么重……这只是
functional dependency的另一个例子.
在下文中,我们依赖于类型Ref被密封的事实,以便我们可以简单地列举替代方案.您的Ref和Reference层次结构保持不变,我们添加一个关系类型Rel来表示两者之间的类型级别对应关系,并进行适当的值级别选择, trait Rel[Ref,T] { def lookup(as: List[A],bs: List[B],cs: List[C])(ref: Ref) : Option[T] } object Rel { implicit val relA = new Rel[ARef,A] { def lookup(as: List[A],cs: List[C])(ref: ARef) : Option[A] = as.find(_.ref == ref) } implicit val relB = new Rel[BRef,B] { def lookup(as: List[A],cs: List[C])(ref: BRef) : Option[B] = bs.find(_.ref == ref) } implicit val relC = new Rel[CRef,C] { def lookup(as: List[A],cs: List[C])(ref: CRef) : Option[C] = cs.find(_.ref == ref) } } 现在我们可以在没有模式匹配或强制转换的情况下重新实现Context,如下所示, trait Context { // ... other stuff ... protected val aList: List[A] = ??? protected val bList: List[B] = ??? protected val cList: List[C] = ??? def get[R <: Ref,T](ref: R)(implicit rel: Rel[R,T]): Option[T] = rel.lookup(aList,bList,cList)(ref) } 我们可以像这样使用这个新定义, object Test { def typed[T](t: => T) {} // For pedagogic purposes only val context = new Context {} val aRef = ARef("my A ref") val myA = context.get(aRef) typed[Option[A]](myA) // Optional: verify inferred type of myA val bRef = BRef("my B ref") val myB = context.get(bRef) typed[Option[B]](myB) // Optional: verify inferred type of myB val cRef = CRef("my C ref") val myC = context.get(cRef) typed[Option[C]](myC) // Optional: verify inferred type of myC } 请注意,get的隐式Rel参数的解析从ref参数的类型计算相应Reference的类型,因此我们可以避免在get的调用站点使用任何显式类型参数. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |