这就是你将如何做这种事情的情况下,这3种特征是密封的。如果他们愿意扩展,它可能会变得更加复杂。
归结为以下几点。您有Fancy
特征,其中A
和B
两种输入类型,以及一种输出类型Out
。您可以定义隐式实例,以便在A
和B
均为ReturnsOne
,Out
将为ReturnsOne
的情况下。在所有其他情况下,您将回退到默认情况下的优先级较低(因为否则您将得到多义性错误),其中Out
总是ReturnsMany
。
scala> :paste
// Entering paste mode (ctrl-D to finish)
sealed trait ReturnCount
sealed trait ReturnsMany extends ReturnCount
sealed trait ReturnsOne extends ReturnCount
sealed trait Fancy[A, B] {
type Out <: ReturnCount
}
object Fancy extends LowerPriority {
type Aux[A,B,Out1 <: ReturnCount] = Fancy[A,B] { type Out = Out1 }
implicit def returnsOne: Fancy.Aux[ReturnsOne,ReturnsOne,ReturnsOne] =
new Fancy[ReturnsOne,ReturnsOne] { type Out = ReturnsOne }
}
trait LowerPriority {
implicit def returnsMany[A,B]: Fancy.Aux[A,B,ReturnsMany] =
new Fancy[A,B] { type Out = ReturnsMany }
}
class Query[R <: ReturnCount] {
def join[R2 <: ReturnCount](q: Query[R2])(implicit fancy: Fancy[R,R2]): Query[fancy.Out] = ???
}
// Exiting paste mode, now interpreting.
defined trait ReturnCount
defined trait ReturnsMany
defined trait ReturnsOne
defined trait Fancy
defined object Fancy
defined trait LowerPriority
defined class Query
scala> :type new Query[ReturnsOne].join(new Query[ReturnsOne])
Query[ReturnsOne]
scala> :type new Query[ReturnsOne].join(new Query[ReturnsMany])
Query[ReturnsMany]
scala> :type new Query[ReturnsMany].join(new Query[ReturnsMany])
Query[ReturnsMany]
scala> :type new Query[ReturnsMany].join(new Query[ReturnsOne])
Query[ReturnsMany]
在真实的场景中你Fancy
可能还需要一个join
方法,其中将包含实际的实现,你Query#join
方法委托:
class Query[R <: ReturnCount] {
def join[R2 <: ReturnCount](q: Query[R2])(implicit fancy: Fancy[R,R2]): Query[fancy.Out] =
fancy.join(this, q)
}
This blog可能是一个很好的起点,以了解更多关于这样的模式。
如果''''R'''的类型为'ReturnsOne''',那么我需要'''R2'''来知道查询返回的结果数量。如果R的类型为'''ReturnsMany''',那么你是对的,它不会产生任何影响,因为它将是''''ManyMany'''无论如何 – shayan
为什么由'R2'确定的结果数量和不是'R'?这里'R'的一般用法是什么? –
@YuvalItzchakov它由R3确定,R3需要R和R2来决定。我正在寻找这个隐含的参数,它使用R和R2来解析R3,使其更加具体 – shayan