任何类型上下文绑定

Posted

技术标签:

【中文标题】任何类型上下文绑定【英文标题】:Any with type context bound 【发布时间】:2016-06-02 07:09:14 【问题描述】:

免责声明:我不确定我是否真的了解类型上下文边界......或任何东西。

是否可以在 scala 中定义一个类型,它是 TypeClass 的实例,其中类型可以是 Any,只要该类型遵守类型上下文绑定。

例如我有一些类型类Printable[T]

Printable 是一个用于可以打印的东西的类型类,它作为类型上下文绑定很有用,因为我可能希望拥有可以采用任何类型的类型类,只要它是可打印的,就像这样:

class SomeContainer[T: Printable](value: T)

据我了解,集合库使用这样的类型上下文边界来处理可以排序、求和等的内容。

但我想要的是type PrintableAnyCollection = SomeCollection[_: Printable]

这是一个可以是不同类型的值的集合,只要所有这些类型都遵守类型上下文绑定,即存在与该类型对应的 Printable[T]

TLDR:

Collection[Any] 几乎可以满足我的要求,因为它可以容纳不同的类型

Collection[T: Printable] 几乎可以满足我的要求,因为它强制集合中的东西是可打印的,但结果是集合只存储一种类型。

Collection[_: Printable] 和/或Collection[Any: Printable] 看起来像是在描述我想要的内容,但语法无效。

【问题讨论】:

【参考方案1】:

你大概正在寻找这样的东西:

// Doesn't work
Collection[T forSome type T: Printable]

但这不起作用,原因是上下文边界只是隐式参数的糖,在编译时解决。特别是,上述类型意味着编译器所做的隐式解析将取决于上述类型的运行时值(每个不同的T 都需要另一个隐式解析)。实际上,您将创建一个方法,其隐式参数列表中的数量可能会在运行时发生变化。

可以说它与 Scala 不兼容。

另一种方法是主动将隐式参数捆绑在某种包装器类型中,并将包装器上的集合参数化为存在。因此,隐式解析发生在创建集合之前。 Miles Sabin 很好地介绍了它here。

简要总结一下这种方法,如下所示:

case class PrintableWrapper[T](unwrap: T)(implicit ev: Printable[T])

Collection[PrintableWrapper[T] forSome type T]

实际上使用集合的条目很麻烦(需要一个虚假的模式匹配来安抚 Scala 的类型检查器)。脱糖的上下文绑定也需要有一个显式的 Printable 实例才能实际打印条目。有关详细信息,请参阅 Miles Sabin 的回答。

这恰好是隐式编码类型类的一种稍微麻烦的方式。

【讨论】:

这个答案最终让我问了很多问题,但最终让我得到了一个可以接受的解决方案。您链接到的另一个线程是对 Scala 中异构列表上的上下文边界的更大问题的精彩讨论。最终我通过放弃类型类和使用子类型解决了我的问题,这是非常不雅的,因为我正在与之交互的库使用类型类,因此我需要一堆垫片,但是使用带有案例类和继承的类型类完全让我失望了复杂性预算。

以上是关于任何类型上下文绑定的主要内容,如果未能解决你的问题,请参考以下文章

Ninject

scala 上下文绑定ClassTagTypeTagClassManifestManifest

Ninject之旅之九:Ninject上下文绑定(附程序下载)

Ninject之旅之八:Ninject插件模型

绑定属性消息在此上下文中不支持值 mtom

面向对象内存模型动态绑定