编写一个可以使用Writer和OutputStream的泛型函数

时间:2011-01-15 23:03:03

标签: scala

我写了几个看起来像这样的函数:

def myWrite(os: OutputStream) = {}
def myWrite(w: Writer) = {}

现在两者非常相似,我想我会尝试编写函数的单个参数化版本。

我开始使用Java OutputStream和Writer中常见的两种方法的类型:

type Writable[T] = {
    def close() : Unit
    def write(cbuf: Array[T], off: Int, len: Int): Unit
}

一个问题是OutputStream写入Byte而Writer写入Char,因此我使用T对类型进行了参数化。

然后我写了我的功能:

def myWrite[T, A[T] <: Writable[T]](out: A[T]) = {}

并尝试使用它:

val w = new java.io.StringWriter()
myWrite(w)                        

结果:

<console>:9: error: type mismatch;
 found   : java.io.StringWriter
 required: ?A[ ?T ]
Note that implicit conversions are not applicable because they are ambiguous:
 both method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
 and method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
 are possible conversion functions from java.io.StringWriter to ?A[ ?T ]
       myWrite(w)

我尝试了其他一些类型和参数的组合,到目前为止无济于事。

我的问题是,是否有办法实现这一点,如果有的话,如何实现。

(请注意,myWrite的实现在内部需要知道参数化write()方法的类型T,因为它需要像在新的ArrayT中一样创建缓冲区。)

更新:“正确”解决方案不起作用,因为编译器中存在错误:https://lampsvn.epfl.ch/trac/scala/ticket/2672

2 个答案:

答案 0 :(得分:1)

首先,您无需在A中参数化myWrite。您的目标类不是通用的!其次,您不需要明确允许子类 - 只需让继承为您做到这一点。

def myWrite[T](out: Writable[T]) = {}

现在该方法可以推断出类型T。只要您因某些原因不需要A的真实类型,这对您有用:

myWrite(new StringWriter)

但是,你会遇到一个问题:

def myWrite[T](out: Writable[T]) = new Array[T](0)  // Doesn't work!

问题是这是通用代码。它不知道T是什么 - 它可能是任何东西!因此,您需要告诉编译器传递标识T的信息:

def myWrite[T : ClassManifest](out: Writable[T]) = new Array[T](0)

(编辑:简化了答案,使其真正有效。)


(编辑:实际上,它不太有效 - 请参阅评论。)

答案 1 :(得分:0)

这有效:

myWrite(w.asInstanceOf[Writable[Char]])

...所以你会认为这会奏效:

implicit def wrToWr(w:java.io.Writer): Writable[Char] = w.asInstanceOf[Writable[Char]]

......但事实并非如此。我不知道为什么不:

scala> myWrite(w)
<console>:17: error: type mismatch;
 found   : java.io.StringWriter
 required: Nothing
       myWrite(w)
               ^

什么都没有来自?