2011-11-24 28 views
3

我知道不可能重載僅在返回類型中有所不同的方法。但我不知道是否有任何智能戰略,這種情況有效地處理:解決超載限制(實現幾種類型的特徵)

trait Reader[A] { def read(in: java.io.DataInput): A } 

trait B; trait C 

def doSomethingB()(implicit r: Reader[B]) =() 
def doSomethingC()(implicit r: Reader[C]) =() 

trait MultiReader extends Reader[B] with Reader[C] { // not possible 
    implicit me = this 

    doSomethingB() 
    doSomethingC() 
} 

通過智能和高效的我的意思是,我想避免混亂和不必要的內部類代這樣的:

trait MultiReader { 
    implicit object RB extends Reader[B] { ... } 
    implicit object RC extends Reader[C] { ... } 

    doSomethingB() 
    doSomethingC() 
} 

編輯

這是一個部分解決方案。 Miles Sabin在最近的幾天裏一直在重讀this gist,這看起來非常鼓舞人心。因此,我可以做到以下幾點:

type Tagged[U] = { type Tag = U } 
type @@[T, U] = T with Tagged[U] 

trait Reader[A] { def read(in: java.io.DataInput @@ A): A } 

然後這個工程:

trait MultiReader { 
    def read(in: java.io.DataInput @@ B): B 
    def read(in: java.io.DataInput @@ C): C 
} 

但是繼承仍然有所打破:

trait MultiReader extends Reader[B] with Reader[C] 

(失敗"self-type MultiReader does not conform to Reader[B]'s selftype Reader[B]")。

回答

1

這仍然實例化一個Function1加上一個匿名Reader爲所需的每個類型參數,但它至少在語法上是更簡潔:

object Reader { 
    implicit def fromFun[A](implicit fun: java.io.DataInput => A): Reader[A] = 
    new Reader[A] { def read(in: java.io.DataInput): A = fun(in) } 
} 
trait Reader[A] { def read(in: java.io.DataInput): A } 

def doSomethingB()(implicit r: Reader[B]): Unit = println(r.read(null)) 
def doSomethingC()(implicit r: Reader[C]): Unit = println(r.read(null)) 

trait MultiReader { 
    implicit def readB(in: java.io.DataInput): B = new B { override def toString = "B" } 
    implicit def readC(in: java.io.DataInput): C = new C { override def toString = "C" } 

    doSomethingB() 
    doSomethingC() 
} 

new MultiReader {} // --> B, C 
0

主要的問題似乎是,即使類型參數不同,Scala也不允許多次實現泛型特徵。有趣的是,儘管調用到標籤的版本正常工作(我故意叫read與輸入標籤BC),它使用時的結構類型,像這樣的失敗:

def doSomethingB()(implicit r: { def read(in: java.io.DataInput @@ B): B }) =() 
def doSomethingC()(implicit r: { def read(in: java.io.DataInput @@ C): C }) =() 

有一個調度的錯誤在這裏,和兩者都會呼叫讀取C


如果有一個約束BC一個類層次結構內,一個想法是使用範圍:

sealed trait B; trait C extends B 

trait UpDownReader[Up, Down] { 
    def read[A >: Down <: Up : Manifest](in: java.io.DataInput): A 
} 

class MultiReader(implicit mfx: Manifest[X], mfy: Manifest[Y]) 
    extends UpDownReader[X, Y] { 

    def read[A >: Y <: X](in: java.io.DataInput)(implicit mf: Manifest[A]): A = 
    (if (mf == mfx) new X {} else new Y {}).asInstanceOf[A] 
} 

這工作:

val m = new MultiReader 
m.read[B](null) 
m.read[C](null) 

然而,考慮到表單的「動態」比較,然後是醜陋的表演,我會稱之爲既不優雅也不高效到A