如何在Scala中对通配符强制执行上下文绑定?
我有一个隐式助手设置如下:如何在Scala中对通配符强制执行上下文绑定?,scala,generics,wildcard,implicit,Scala,Generics,Wildcard,Implicit,我有一个隐式助手设置如下: trait Helper[T] { def help(entry: T): Unit } object Helpers { implicit object XHelper extends Helper[X] { override def help(entry: X): Unit = {println("x")} } implicit object YHelper extends Helper[Y] { override def hel
trait Helper[T] {
def help(entry: T): Unit
}
object Helpers {
implicit object XHelper extends Helper[X] {
override def help(entry: X): Unit = {println("x")}
}
implicit object YHelper extends Helper[Y] {
override def help(entry: Y): Unit = {println("y")}
}
def help[T](entry: T)(implicit helper: Helper[T]): Unit = {
helper.help(entry)
}
}
我想建立一个元素集合,并对每个元素运行help
。但是,下面给出了一个编译器错误,因为我们不能保证所有元素都有匹配的Helper
s:
val data = Seq[_](new X(), new Y())
data.foreach(entry => Helpers.help(entry))
如果我们有一个泛型类型
T
,我们可以用[T:Helper]
对它强制执行隐式约束,但这对\uuuuz
不起作用。如何确保数据
的每个元素都有一个匹配的助手
?像Seq
这样的类型是不可能的,因为它只针对一个元素类型进行参数化,而该元素类型对其所有元素都是通用的
但是,您可以通过HLists和多态函数(Poly)实现这一点:
X类
Y类
特质帮助者[T]{
def帮助(条目:T):单位
}
对象帮助程序{
隐式对象XHelper扩展辅助对象[X]{
覆盖def帮助(条目:X):单位=println(“X”)
}
隐式对象YHelper扩展辅助对象[Y]{
覆盖def帮助(条目:Y):单位=打印项次(“Y”)
}
}
进口不成形_
对象辅助对象扩展Poly1{
隐式def tCase[T:Helper]:Case.Aux[T,Unit]=
at(隐式地[Helper[T]].help()
}
val hlist=新X::新Y::HNil
hlist.map(助手)
//输出:
x
Y
在Scala上下文绑定中,比如类A[T:Typeclass]
只是类A[T](隐式ev:Typeclass[T])
的语法糖。与T:Super
不同,上下文绑定实际上不是类型签名的一部分,因此不能有像valb:Box[T:Typeclass]
这样的签名
如果要对某些容器的元素运行typeclass操作,则必须将相关的typeclass实例与容器中的值打包在一起
可能的实现方式如下所示:
import language.higherKinds
import language.implicitConversions
// Class that packs values with typeclass instances
class WithTC[T, TC[_]](t: T)(implicit tc: TC[T]) {
// Some helper methods to simplify executing typeclass operations
// You may just make `t` and `tc` public, if you wish.
def apply[U](op: (TC[T], T) => U) = op(tc, t)
def apply[U](op: T => TC[T] => U) = op(t)(tc)
}
object WithTC {
// Implicit conversion to automatically wrap values into `WithTC`
implicit def apply[T, TC[_]](t: T)(implicit tc: TC[T]): WithTC[T, TC] =
new WithTC(t)(tc)
}
然后,您可以使用存在类型的元素创建一个序列:
import Helpers._
val data: Seq[(T WithTC Helper) forSome { type T }] = Seq(new X(), new Y())
// The following lines produce equivalent results
data.foreach(_(_ help _))
data.foreach(_(t => implicit tc => Helpers.help(t)))
data.foreach(_(t => Helpers.help(t)(_)))
并对序列元素执行typeclass操作:
import Helpers._
val data: Seq[(T WithTC Helper) forSome { type T }] = Seq(new X(), new Y())
// The following lines produce equivalent results
data.foreach(_(_ help _))
data.foreach(_(t => implicit tc => Helpers.help(t)))
data.foreach(_(t => Helpers.help(t)(_)))
你能用一个新的特征来扩展类型
X
和Y
,比如说trait HasHelp
?不,不幸的是,代码不在我的控制范围之内。这让我感到惊讶,因为我可以做Seq[\uu]这样的事情,比如T:Helper
只是的语法糖(隐式ev:Helper[T])
在一个方法中,所以我不确定它如何能够与值的参数化一起工作。