我知道不可能重载仅在返回类型上有所不同的方法。但我想知道是否有任何明智的策略可以有效地处理这种情况:
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]"
}失败。
答案 0 :(得分: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
答案 1 :(得分:0)
主要问题似乎是Scala不允许多次实现一般特征,即使类型参数不同。有趣的是,虽然调用标记版本可以正常工作(我可以故意使用标记为read
或B
的输入调用C
,但在使用结构类型时会失败,如下所示:
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
。
如果存在B
和C
在一个类层次结构中的约束,则一个想法是使用边界:
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
,我认为这既不优雅也不高效。