我正在尝试找到一种解决方法,将用户定义的隐式隐藏到某些库代码的调用站点中。我有类似的东西
Prune
我想补充一下这样的事情
//library code
trait Fruit { def foo: Unit }
class Apple extends Fruit {
def foo: Unit = {
// a bunch of imperative code
}
}
class Pear extends Fruit // etc
我试图将其纳入范围的想法将是这样的:
// library code
trait Fruit { def foo[+A <: Fruit](implicit fi: FruitImplicit[A]): Unit }
class Apple extends Fruit {
def foo[Apple](implicit fi: FruitImplicit[Apple]): Unit = {
// a bunch of imperative code
fi.aReallyImportantMethod
}
}
class Pear extends Fruit // etc
trait FruitImplicits[+A <: Fruit]{
def mark: Unit = Unit // default implementation that normally would be used
}
// user code
implicit val appleImplicit: FruitImplicit[Apple] = new FruitImplicit[Apple] {
def mark: Unit = println("YOLO")
}
我知道我遗漏了一些东西(这显然不能编译)。有没有解决的办法?我一直认为有一种方法可以将// library code
class Apple extends Fruit {
object FruitOps extends LowPriorityFruitImplicits with FruitImplicits[A] {}
import FruitOps._
def foo[Apple](implicit fi: FruitImplicit[Apple]): Unit = {
// a bunch of imperative code
fi.aReallyImportantMethod
}
}
静态转换为FruitImplicits
,这会为该特定类型带来隐含的内容。但是,这需要创建一个本身就是其子类型的类型。
或许我疯了,这是一个可怕的想法。有什么想法吗?
答案 0 :(得分:1)
我认为这是一个可怕的想法,当然,但我也认为你想做的事情是可能的(如果我理解正确的话)。
一个问题是,Apple
中foo
的{{1}}类型参数会影响Apple
类型。如果你想引用Apple
中的子类型,你需要使用 F - 有界多态的东西:
Fruit
(为了遵循副作用代码的最佳实践,我添加了一组额外的括号,但它们不是必需的。)
您的trait Fruit[F <: Fruit[F]] {
def foo()(implicit fi: FruitImplicit[F]): Unit
}
将如下所示:
FruitImplicit
在这里,我们提供了一个默认操作,如果用户没有为我们调用trait FruitImplicit[A <: Fruit[A]] {
def mark(): Unit
}
object FruitImplicit {
implicit def defaultAction[F <: Fruit[F]]: FruitImplicit[F] =
new FruitImplicit[F] {
def mark(): Unit = println("default")
}
}
的类型提供隐式操作,将会使用该操作。
现在您的实施将如下所示:
mark
然后:
class Apple extends Fruit[Apple] {
def foo()(implicit fi: FruitImplicit[Apple]): Unit = {
println("This is an apple")
fi.mark()
}
}
class Pear extends Fruit[Pear] {
def foo()(implicit fi: FruitImplicit[Pear]): Unit = {
println("This is a pear")
fi.mark()
}
}
但如果用户提供隐含的......
scala> val apple = new Apple
apple: Apple = Apple@7bb35c46
scala> val pear = new Pear
pear: Pear = Pear@777bd4a2
scala> apple.foo()
This is an apple
default
scala> pear.foo()
This is a pear
default
...它将被用来代替该类型的默认值。