2013-03-11 24 views
1

我有两个第三方库的特征,我试图将它们融入到我自己的特质中。它们都定义为implicit val,其名称为log如何混合具有相同名称但不同类型的隐式vals的特征?

但是,他们是不同的类型 - 一个是SLF4J Logger,另一个是喷雾LoggingContext(这实际上是一个Akka LoggingAdapter)。事实上,第二个特征来自Spray,这是一个HttpServer。 (不是您可以在Github上找到的最新版本,它不再有val)。

所以,这里的代码(重命名,因为它是专有库中的一个,剪断喷雾代码只显示相关部分):

object LibraryOneShim { 
    trait LibraryOne { 
     implicit val log: org.slf4j.Logger = ... 
    } 
} 

// https://github.com/spray/spray/blob/a996a5b6bdd830e613583fed86e87bf049fdb8c0/spray-routing/src/main/scala/spray/routing/HttpService.scala 
trait HttpService extends Directives { 
    val log = LoggingContext.fromActorRefFactory // this is a LoggingContext/LoggingAdapter 
} 

trait MyTrait extends HttpService with LibraryOne { 
    val myRoute = ... 
} 

class MyActor extends Actor with MyTrait { 
    def receive = runRoute(myRoute) 
} 

这不会编译。编译器抱怨:

error: overriding lazy value log in trait HttpService of type java.lang.Object with spray.util.LoggingContext; lazy value log in trait LibraryOne$class of type org.slf4j.Logger needs `override' modifier trait DemoService extends HttpService with LibraryOne {

有没有什么办法可以将这两种特性混合在一起?

回答

4

至于我可以告诉的唯一方法是创建一个CombinedLogger

class CombinedLogger(l1:Logger, l2:LoggingAdapter) extends Logger with LoggingAdapter { 
    // proxy methods to the correct logger 
} 

如果这两个记录仪被宣布为def你可以使用这样的:

override def log = new CombinedLogger(super[LibraryOne].log, super[HttpService].log) 

在这种情况下,它棘手,因为它们被定义为val,它告诉Scala编译器它们是不会改变的单个值。正因为如此,它不会让你致电super.log。所以你需要复制重写特征的逻辑。

在这种情况下的另一个棘手的部分是,你需要在CombinedLogger代理50+方法。

+1

我明白了。是的,这可能会起作用,但是... ick。我很高兴这是一个有争议的问题。这个故事的道德,不要在你的图书馆中使用像“log”这样的常用名字的vals ... – ryryguy 2013-03-12 16:31:43

+1

如果你这样做,至少用'def'声明它们, – EECOLOR 2013-03-12 18:31:51

相关问题