Scala 上下文边界
Scala context bounds
在 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)
或者干脆
val somethingFromInt = implicitly[HasBuild[Int]].build(1)
如何表达范围内具有适当隐式 HasBuild
对象的任何元素的 Seq
类型?如果没有太多魔法和外部库,这可能吗?
Seq[WhatTypeGoesHere]
- 我应该能够为每个元素找到合适的 HasBuild
这显然不能编译:
val buildables: Seq[_: HasBuild] = ???
首先,与某些评论相反,您依赖于上下文界限。为 T
请求隐式类型 class 实例就是所谓的 "context bound".
你想要的是可以实现的,但不是微不足道的,当然如果没有其他库也不是。
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)
}
现在您可以执行以下操作:
Builder(5).and("string").build()
这将从所有单独的隐式类型 class 实例调用 build
方法,并为您提供结果列表,其中每个结果的类型为 Something
。它依赖于所有构建方法的下限为 Something
的事实,例如,根据您的示例:
trait HasBuild[T] {
def build(buildable: T): Something
}
Basically I'd like to be able to handle unrelated types in a common way (e.g.: 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.
你可以做的事情:
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)
}
现在(假设您添加一个 HasBuild[String]
用于演示):
val buildables: Seq[HasHasBuild[_]] = Seq(1, "a")
编译,但是
val buildables1: Seq[HasHasBuild[_]] = Seq(1, "a", 1.0)
没有。当您只有 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(_))
在 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)
或者干脆
val somethingFromInt = implicitly[HasBuild[Int]].build(1)
如何表达范围内具有适当隐式 HasBuild
对象的任何元素的 Seq
类型?如果没有太多魔法和外部库,这可能吗?
Seq[WhatTypeGoesHere]
- 我应该能够为每个元素找到合适的 HasBuild
这显然不能编译:
val buildables: Seq[_: HasBuild] = ???
首先,与某些评论相反,您依赖于上下文界限。为 T
请求隐式类型 class 实例就是所谓的 "context bound".
你想要的是可以实现的,但不是微不足道的,当然如果没有其他库也不是。
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)
}
现在您可以执行以下操作:
Builder(5).and("string").build()
这将从所有单独的隐式类型 class 实例调用 build
方法,并为您提供结果列表,其中每个结果的类型为 Something
。它依赖于所有构建方法的下限为 Something
的事实,例如,根据您的示例:
trait HasBuild[T] {
def build(buildable: T): Something
}
Basically I'd like to be able to handle unrelated types in a common way (e.g.: 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.
你可以做的事情:
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)
}
现在(假设您添加一个 HasBuild[String]
用于演示):
val buildables: Seq[HasHasBuild[_]] = Seq(1, "a")
编译,但是
val buildables1: Seq[HasHasBuild[_]] = Seq(1, "a", 1.0)
没有。当您只有 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(_))