2013-03-11 57 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

相關問題