[英]Scala context bounds
Using context bounds in scala you can do stuff like 在Scala中使用上下文范围,您可以执行以下操作
trait HasBuild[T] {
def build(buildable: T): Something
}
object Builders {
implict object IntBuilder extends HasBuild[Int] {
override def build(i: Int) = ??? // Construct a Something however appropriate
}
}
import Builders._
def foo[T: HasBuild](input: T): Something = implicitly[HasBuild[T]].build(1)
val somethingFormInt = foo(1)
Or simply 或者简单地
val somethingFromInt = implicitly[HasBuild[Int]].build(1)
How could I express the type of a Seq
of any elements that have an appropriate implicit HasBuild
object in scope? 如何在范围内具有适当的隐式
HasBuild
对象的任何元素的Seq
类型? Is this possible without too much magic and external libraries? 如果没有太多的魔术和外部库,这可能吗?
Seq[WhatTypeGoesHere]
- I should be able to find the appropriate HasBuild
for each element Seq[WhatTypeGoesHere]
-我应该能够为每个元素找到合适的HasBuild
This obviously doesn't compile: 这显然不能编译:
val buildables: Seq[_: HasBuild] = ???
Basically I'd like to be able to handle unrelated types in a common way (eg: build), without the user wrapping them in some kind of adapter manually - and enforce by the compiler, that the types actually can be handled.
基本上,我希望能够以一种通用的方式(例如:构建)处理不相关的类型,而无需用户手动将它们包装在某种适配器中,并由编译器强制执行,这些类型实际上可以被处理。 Not sure if the purpose is clear.
不知道目的是否明确。
Something you can do: 您可以执行的操作:
case class HasHasBuild[A](value: A)(implicit val ev: HasBuild[A])
object HasHasBuild {
implicit def removeEvidence[A](x: HasHasBuild[A]): A = x.value
implicit def addEvidence[A: HasBuild](x: A): HasHasBuild[A] = HasHasBuild(x)
}
and now (assuming you add a HasBuild[String]
for demonstration): 现在(假设您添加了一个
HasBuild[String]
进行演示):
val buildables: Seq[HasHasBuild[_]] = Seq(1, "a")
compiles, but 编译,但是
val buildables1: Seq[HasHasBuild[_]] = Seq(1, "a", 1.0)
doesn't. 没有。 You can use methods with implicit
HasBuild
parameters when you have only a HasHasBuild
: 只有
HasHasBuild
时,可以使用带有隐式HasBuild
参数的方法:
def foo1[A](x: HasHasBuild[A]) = {
import x.ev // now you have an implicit HasBuild[A] in scope
foo(x.value)
}
val somethings: Seq[Something] = buildables.map(foo1(_))
First things first, contrary to some of the comments, you are relying on context bounds. 首先,与某些评论相反,您所依赖的是上下文范围。 Requesting an implicit type class instance for a
T
is what you call a "context bound". 为
T
请求隐式类型类实例就是您所说的“上下文绑定”。
What you want is achievable, but not trivial and certainly not without other libraries. 您想要的是可以实现的,但并非无关紧要的,而且当然没有其他库也不是没有。
import shapeless.ops.hlist.ToList
import shapeless._
import shapeless.poly_
object builder extends Poly1 {
implicit def caseGeneric[T : HasBuilder] = {
at[T](obj => implicitly[HasBuilder[T]].build(obj))
}
}
class Builder[L <: HList](mappings: L) {
def build[HL <: HList]()(
implicit fn: Mapper.Aux[builder.type, L, HL],
lister: ToList[Something]
) = lister(mappings map fn)
def and[T : HasBuilder](el: T) = new Builder[T :: L](el :: mappings)
}
object Builder {
def apply[T : HasBuilder](el: T) = new Builder(el :: HNil)
}
Now you might be able to do stuff like: 现在您可以执行以下操作:
Builder(5).and("string").build()
This will call out the build
methods from all the individual implcit type class instances and give you a list of the results, where every result has type Something
. 这将召唤出
build
从所有个体implcit类型类实例的方法,给你的结果,其中每个结果类型的列表Something
。 It relies on the fact that all the build methods have a lower upper bound of Something
, eg as per your example: 它基于所有构建方法都具有
Something
的下限的事实,例如,按照您的示例:
trait HasBuild[T] {
def build(buildable: T): Something
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.