解决超载限制(实现几种类型的特征)

时间:2011-11-24 01:47:46

标签: scala overloading

我知道不可能重载仅在返回类型上有所不同的方法。但我想知道是否有任何明智的策略可以有效地处理这种情况:

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]"}失败。

2 个答案:

答案 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不允许多次实现一般特征,即使类型参数不同。有趣的是,虽然调用标记版本可以正常工作(我可以故意使用标记为readB的输入调用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


如果存在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,我认为这既不优雅也不高效。