我有一个在其他类中注入的类中定义的隐式类,如
class A {
implicit class B(s: String) {
def b = ???
}
}
class C(a: A) {}
有没有办法从C类访问隐式类B(特别是它的方法b),而无需显式导入它? (请注意,A类不能成为特征,因为它也注入了一些类。)
答案 0 :(得分:2)
解决方案1 (导入a._
)
嗯,是的,正如评论中已经提到的,根据您的要求,为什么您不能在a._
的正文中导入C
并不明显:
class A {
implicit class B(arg: String) {
def b: String = ???
}
}
class C(a: A) {
import a._
{
println("hello".b)
}
}
这一行真的不会伤害任何人。
如果您仍然不喜欢它,那么问题可能出在其他地方。这是我的第二个提议。
解决方案2 (将类似类词类的A
- 界面与.b
分开 - 语法)
另一个解决方案不是减少代码中import
的数量,而且它甚至不会将B
保留在A
内。但它可能会解决另一个问题,您可能只是非常清楚:它将A
提供的功能与B
提供的语法分开。
以下代码段的结构受Scala Cats库的设计启发,该库遵循一个非常明确的隐式声明策略,始终将类型类定义与语法分开。
主要思想是:
AIntf
的实现提供实际功能B
仅提供了一些额外的" pimp-my-library" -style方法我们希望将这两件事分开。
以下是如何将它们分开,从而避免在import a._
内部C
。首先,定义描述A
提供的功能的界面:
trait AIntf {
def usefulOperationOnStrings(s: String): String
}
然后你可以用几个不同的A来实现它:
class A extends AIntf {
def usefulOperationOnStrings(s: String): String = "<foo>" + s + "</foo>"
}
class A2 extends AIntf {
def usefulOperationOnStrings(s: String): String = s.toUpperCase
}
请注意,对象B
已从A
中消失。相反,它会在单独的syntax
- 包中移动,并重命名为A_Ops
。方法b
也重命名为a
:
object syntax /* should be package, object only for script */ {
object a {
class A_Ops(wrapped: String, ai: AIntf) {
def a: String = ai.usefulOperationOnStrings(wrapped)
}
implicit def everyStringHasAOps(s: String)(implicit ai: AIntf): A_Ops = {
new A_Ops(s, ai)
}
}
}
这是您使用它的方式:
A_Intf
syntax.a._
a
- C
的参数声明为隐式"string".a
内使用C
语法而无需进一步导入。在代码中:
import myproject.AIntf
import myproject.syntax.a._
class C(implicit val a: AIntf) {
{
println("hello".a)
}
}
现在AIntf
和语法.a
的实现变得独立。您可以注入A2
而不是A
。或者,您可以将语法从"str".a
更改为"str".somethingEntirelyDifferent
。
完整的代码段:
import scala.language.implicitConversions
object myproject /* should be package, object only for script */ {
trait AIntf {
def usefulOperationOnStrings(s: String): String
}
object syntax /* should be package, object only for script */ {
object a {
class A_Ops(wrapped: String, ai: AIntf) {
def a: String = ai.usefulOperationOnStrings(wrapped)
}
implicit def everyStringHasAOps(s: String)(implicit ai: AIntf): A_Ops = {
new A_Ops(s, ai)
}
}
}
class A extends AIntf {
def usefulOperationOnStrings(s: String): String = "<foo>" + s + "</foo>"
}
class A2 extends AIntf {
def usefulOperationOnStrings(s: String): String = s.toUpperCase
}
}
import myproject.AIntf
import myproject.syntax.a._
class C(implicit val a: AIntf) {
{
println("hello".a)
}
}
val c1 = new C()(new myproject.A)
val c2 = new C()(new myproject.A2)
// prints:
// <foo>hello</foo>
// HELLO
不幸的是,我不清楚guice
将如何处理隐式参数,还没有尝试过。它可能会迫使你写
class C @Inject()(val a: AIntf) {
implicit aintf: AIntf = a
...
}
然后变得比第一部分中提到的简单import
长。
答案 1 :(得分:0)
正如评论中所述,只是import a._
:
class A {
implicit class B(s: String) {
def b: String = "hello "+ s
}
}
class C(a: A){
import a._
val hello = "world".b
}
val c = new C(new A)
c.hello // "hello world"