在函数参数中使用多个 Scala TypeClass 实例
Using multiple Scala TypeClass instances in function parameters
我创建了一组案例 classes,我想使用 Scala Typeclass 实现不同的行为。下面的代码示例按预期工作。
case class QueryBuilder(s: String)
abstract class A()
case class B() extends A
case class C() extends A
abstract class S()
case class X() extends S
case class Y() extends S
trait BuildableQuery[T] {
def toQuery(p: T): QueryBuilder
}
implicit object BQueryBuilder extends BuildableQuery[B] {
def toQuery(p: B): QueryBuilder = { QueryBuilder("Query of B") }
}
implicit object CQueryBuilder extends BuildableQuery[C] {
def toQuery(p: C): QueryBuilder = { QueryBuilder("Query of C") }
}
implicit object XQueryBuilder extends BuildableQuery[X] {
def toQuery(p: X): QueryBuilder = { QueryBuilder("Query of X") }
}
implicit object YQueryBuilder extends BuildableQuery[Y] {
def toQuery(p: Y): QueryBuilder = { QueryBuilder("Query of Y") }
}
def toQuery[A: BuildableQuery](value: A): QueryBuilder =
(implicitly[BuildableQuery[A]]).toQuery(value)
println(toQuery(B()).s) // Query of B
println(toQuery(C()).s) // Query of C
println(toQuery(X()).s) // Query of X
println(toQuery(Y()).s) // Query of Y
到目前为止一切顺利。我可以将方法 toQuery
与任何定义的类型一起使用。
我的问题:我想通过组合抽象 classes A
和 S
.[=18 来创建一个 returns 和 BuildableQuery
的函数=]
我尝试创建一个新的隐式对象,它定义了一个新案例 class 的行为,该案例由 A
和 S
的组合组成。在函数中使用它时,它不会编译。
case class AS[I <: A, P <: S](a: I, s: P)
implicit object ASQueryBuilder extends BuildableQuery[AS[B, X]] {
def toQuery(p: AS[B, X]): QueryBuilder = { QueryBuilder("Query of BX") }
}
// Does not compile...
// Error: could not find implicit value for evidence parameter of type BuildableQuery[AS[A,S]]
def func(a: A, s: S): QueryBuilder = toQuery(AS(a,s))
// Does not compile...
// Error: could not find implicit value for evidence parameter of type BuildableQuery[AS[I,P]]
def func2[I <: A: BuildableQuery, P <: S: BuildableQuery](a: I, s: P): QueryBuilder =
toQuery(AS(a,s))
这个问题有解决方案吗?
更新
如果您只想为 I
和 P
的特定值定义 AS[I, P]
个实例,那也是可能的——您可以在您的问题中定义 ASQueryBuilder
,然后在您的方法中需要一个使用类型 class:
的实例
def func(a: A, s: S)(implicit bq: BuildableQuery[AS[A, S]]): QueryBuilder = toQuery(AS(a,s))
def func2[I <: A: BuildableQuery, P <: S: BuildableQuery](a: I, s: P)(implicit
bq: BuildableQuery[AS[I, P]]
): QueryBuilder = toQuery(AS(a, s))
现在这些只有在合适的实例可用时才会编译。
原回答
听起来您想创建通用实例,而不仅仅是 AS[B, X]
。您可以使用通用方法执行此操作:
implicit def ASQueryBuilder[I <: A, P <: S]: BuildableQuery[AS[I, P]] =
new BuildableQuery[AS[I, P]] {
def toQuery(p: AS[I, P]): QueryBuilder = { QueryBuilder("Query of AS") }
}
现在您的示例可以编译了。
附带说明一下,使用相同的名称 (toQuery
) 作为类型 class 方法和类型 class 语法方法可能会使事情变得有点困难。您可能想重命名一个,例如语法方法在类型 class 实例的 toQuery
.
的定义中可用
我创建了一组案例 classes,我想使用 Scala Typeclass 实现不同的行为。下面的代码示例按预期工作。
case class QueryBuilder(s: String)
abstract class A()
case class B() extends A
case class C() extends A
abstract class S()
case class X() extends S
case class Y() extends S
trait BuildableQuery[T] {
def toQuery(p: T): QueryBuilder
}
implicit object BQueryBuilder extends BuildableQuery[B] {
def toQuery(p: B): QueryBuilder = { QueryBuilder("Query of B") }
}
implicit object CQueryBuilder extends BuildableQuery[C] {
def toQuery(p: C): QueryBuilder = { QueryBuilder("Query of C") }
}
implicit object XQueryBuilder extends BuildableQuery[X] {
def toQuery(p: X): QueryBuilder = { QueryBuilder("Query of X") }
}
implicit object YQueryBuilder extends BuildableQuery[Y] {
def toQuery(p: Y): QueryBuilder = { QueryBuilder("Query of Y") }
}
def toQuery[A: BuildableQuery](value: A): QueryBuilder =
(implicitly[BuildableQuery[A]]).toQuery(value)
println(toQuery(B()).s) // Query of B
println(toQuery(C()).s) // Query of C
println(toQuery(X()).s) // Query of X
println(toQuery(Y()).s) // Query of Y
到目前为止一切顺利。我可以将方法 toQuery
与任何定义的类型一起使用。
我的问题:我想通过组合抽象 classes A
和 S
.[=18 来创建一个 returns 和 BuildableQuery
的函数=]
我尝试创建一个新的隐式对象,它定义了一个新案例 class 的行为,该案例由 A
和 S
的组合组成。在函数中使用它时,它不会编译。
case class AS[I <: A, P <: S](a: I, s: P)
implicit object ASQueryBuilder extends BuildableQuery[AS[B, X]] {
def toQuery(p: AS[B, X]): QueryBuilder = { QueryBuilder("Query of BX") }
}
// Does not compile...
// Error: could not find implicit value for evidence parameter of type BuildableQuery[AS[A,S]]
def func(a: A, s: S): QueryBuilder = toQuery(AS(a,s))
// Does not compile...
// Error: could not find implicit value for evidence parameter of type BuildableQuery[AS[I,P]]
def func2[I <: A: BuildableQuery, P <: S: BuildableQuery](a: I, s: P): QueryBuilder =
toQuery(AS(a,s))
这个问题有解决方案吗?
更新
如果您只想为 I
和 P
的特定值定义 AS[I, P]
个实例,那也是可能的——您可以在您的问题中定义 ASQueryBuilder
,然后在您的方法中需要一个使用类型 class:
def func(a: A, s: S)(implicit bq: BuildableQuery[AS[A, S]]): QueryBuilder = toQuery(AS(a,s))
def func2[I <: A: BuildableQuery, P <: S: BuildableQuery](a: I, s: P)(implicit
bq: BuildableQuery[AS[I, P]]
): QueryBuilder = toQuery(AS(a, s))
现在这些只有在合适的实例可用时才会编译。
原回答
听起来您想创建通用实例,而不仅仅是 AS[B, X]
。您可以使用通用方法执行此操作:
implicit def ASQueryBuilder[I <: A, P <: S]: BuildableQuery[AS[I, P]] =
new BuildableQuery[AS[I, P]] {
def toQuery(p: AS[I, P]): QueryBuilder = { QueryBuilder("Query of AS") }
}
现在您的示例可以编译了。
附带说明一下,使用相同的名称 (toQuery
) 作为类型 class 方法和类型 class 语法方法可能会使事情变得有点困难。您可能想重命名一个,例如语法方法在类型 class 实例的 toQuery
.