2011-01-15 4 views
4

Ich schrieb ein paar Funktionen übernehmen können, die wie folgt aussehen:eine generische Funktion zu schreiben, die ein Schriftsteller sowie ein Output

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

Nun sind beide sehr ähnlich sind, und ich dachte, ich würde versuchen, einen einzigen zu schreiben parametrisierte Version der Funktion.

ich mit einem Typ mit den beiden Methoden begonnen, die in der Java Output und Writer gemeinsam sind:

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

Ein Problem ist, dass Output schreibt Byte und Verfasser schreiben Char, so parametrisiert ich den Typen mit T.

Dann schreibe ich meine Funktion:

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

und versuchen, es zu benutzen:

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

Ergebnis:

<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) 

ich ein paar andere Kombinationen der Typen und Parameter versucht, Bis jetzt vergeblich.

Meine Frage ist, ob es einen Weg gibt, dies überhaupt zu erreichen, und wenn ja wie.

(Beachten Sie, dass die Umsetzung von myWrite benötigt, intern, um den Typ zu wissen T, die die Methode write() parametrisiert, weil es einen Puffer wie in neuen ArrayT erstellen muss.)

UPDATE: Der " richtige“Lösung funktioniert nicht, weil ein Fehler in dem Compiler: https://lampsvn.epfl.ch/trac/scala/ticket/2672

Antwort

0

Dies funktioniert:

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

... so würden Sie denken, dies funktionieren würde:

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

... aber es nicht. Ich habe keine Ahnung warum nicht:

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

Woher kommt nichts?

+0

Sie müssen den Cast nicht zwingen mit 'asInstanceOf'; ein einfacher 'myWrite (w: Writable [Char])' sollte den Trick machen, da formal 'Writable [Char]' bei den Typdefinitionen als Oberklasse von 'Writer' fungiert. Außerdem kommt 'Nothing' von der Typ-Inferenz-Engine, die den genauesten möglichen Typ verwendet. 'Nothing' ist eine Unterklasse jeder anderen Klasse, also benutzt sie das, wenn sie nicht gezwungen wird, etwas anderes zu tun (und es merkt nicht, dass sie gezwungen ist, etwas anderes zu tun; sie denkt, dass sie' T' unabhängig von 'A' auflösen kann). –

+0

Ah, das erklärt viel. Vielen Dank. –

1

Zuerst müssen Sie A in myWrite nicht parametrieren. Ihre Zielklassen sind nicht generisch! Zweitens müssen Sie Unterklassen nicht explizit zulassen - lassen Sie einfach die Vererbung für Sie tun.

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

Jetzt kann die Methode den Typ T ableiten. Solange Sie aus irgendeinem Grund nicht auch die wahre Art von A müssen, wird dies für Sie arbeiten:

myWrite(new StringWriter) 

aber Sie gehen in ein Problem laufen:

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

Das Problem ist, dass dies ein generischer Code ist.Es weiß nicht, was T ist - es könnte alles sein! So müssen Sie den Compiler sagen, in Informationen zu übergeben, die T identifiziert:

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

(Edit:. Vereinfacht die Antwort, damit es funktioniert tatsächlich)


(Edit: tatsächlich, es doesn‘ t ziemlich Arbeit - siehe Kommentare.)

+0

Dies funktioniert immer noch nicht: Ich bekomme 'Fehler: abgeleitete Typargumente [Nothing, java.io.FileWriter] entsprechen nicht der Methode myWrite's Typparameter bounds [T, A <: Writable [T]]'! – ebruchez

+0

BTW wenn du sagst "es weiß nicht, was' T' ist ": als ich Mensch kann ich den Typ perfekt ableiten: Ich stelle fest, dass Writer meinem Writable entspricht, welches zufällig eine write() Methode mit einem Array hat Verkohlen]. So, jetzt weiß ich, dass ich einen Beschreibbaren [Char] habe. Es scheint, dass zumindest in einem solchen Fall das Typsystem in der Lage sein sollte, auf T zu schließen. Ich weiß nicht, wie das Typsystem tief arbeitet und ob diese Art der Inferenz kompatibel ist oder nicht, sondern wie ein menschliches Ich kann definitiv schließen. Wie auch immer, es wäre großartig, wenn es aus der Schachtel heraus funktionieren würde, denn jetzt könnte ich mich mit den Implicits begnügen, wenn man sie zur Arbeit bringen könnte! – ebruchez

+0

Es gibt einen komplizierten Weg und einen einfachen Weg, um das Problem in meinem ursprünglichen Beitrag zu beheben (Ich hatte zu viele implizite Sachen in der REPL auf einmal und war verwirrt darüber, warum die Dinge funktionierten). Ich ging auf den einfachen Weg, was wahrscheinlich genug ist. Sie können einen weiteren Wrapper hinzufügen, um es kompliziert zu machen, wenn Sie den eigentlichen Typ von 'A' anstelle von dessen Oberklasse' Writable [Char] 'oder' Writable [Byte] 'brauchen. –

Verwandte Themen