2011-01-15 6 views
4

を取ることができ、一般的な機能を書く私はこのように見える機能のカップルを書いた:は、ライターなどのOutputStream

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 
} 

1つの問題は、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) 

私はパラメータの型と他のいくつかの組み合わせを試してみました、これまでのところ役に立たない。

私の質問は、これを達成するための方法があるかどうか、もしそうならば。

(それは新しいArrayTのようにバッファを作成する必要があるためmyWriteの実装は、write()メソッドをparametrizesタイプTを知るために、内部的に、必要になることに注意してください。)

UPDATE: "をhttps://lampsvn.epfl.ch/trac/scala/ticket/2672

答えて

0

これは動作します:

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

ので、あなたはこれが働くと思うだろう...:

をコンパイラのバグがあるため、正しい」解決策は動作しません。 210
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) 
      ^

どこから来ていませんか?

+0

'asInstanceOf'を使って強制的にキャストする必要はありません。形式的に 'Writable [Char]'は型定義が与えられた 'Writer'のスーパークラスとして機能するので、単純な' myWrite(w:Writable [Char]) 'はこのトリックを行うべきです。また、「Nothing」は、可能な限り最も特殊な型を使用する型推論エンジンに由来します。 'Nothing'は他のすべてのクラスのサブクラスなので、そうしなければ強制的に使われます(そうでなければ強制されていることに気付かず、' A'とは独立に 'T'を解決できると思っています)。 –

+0

ああ、それはたくさん説明します。ありがとう。 –

1

まず、AmyWriteにパラメータ化する必要はありません。ターゲットクラスは一般的ではありません!第二に、サブクラスを明示的に許可する必要はありません。継承はあなたのためのトリックとなります。

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) 

(編集:それは実際に動作させるために答えを簡素化)


(編集:実際には、それはdoesnの

+0

これはまだ動作しません:エラー:推論された型引数[Nothing、java.io.FileWriter]がメソッドmyWriteの型パラメータbounds [T、A <:Writable [T]] 'に適合しません! – ebruchez

+0

私は人間のようにタイプを完全に推論することができます:WriterがWritableに対応していることに気付きました。WritableはArray()メソッドを持つwrite()メソッドを持っています。 Char]。だから私はWritable [Char]を持っていることを知っています。少なくともこのような場合、型システムはTを推論することができるはずです。私は型システムがどのように深く働くか、そしてこの種の推論が互換性があるかどうかはわかりませんが、人間I間違いなく推論することができる。とにかく、それが箱から出ていればそれは素晴らしいだろうが、今は仕事につくことができたら、私は黙って解決することができた! – ebruchez

+0

オリジナルの投稿で問題を解決するには、複雑な方法と簡単な方法があります(私はあまりにも多くの暗黙のREPLを一度に持っていて、何がうまくいったのか混乱しました)。私は簡単な方法で行ったが、これで十分だろう。スーパークラス 'Writable [Char]'や 'Writable [Byte]'ではなく、 'A'の実際の型が必要な場合は、複雑な方法で別のラッパーを追加することができます。 –

関連する問題