2010-07-13 18 views
6

tentativo di implementare il codice simile a quello riscontrato nell'esempio ordine-funzioni superiore da http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6Scala ActionListener/tipo funzione anonima disadattamento

val button = new JButton("test") 
button.addActionListener{ e:ActionEvent => println("test") } 
add(button) 

porta alla seguente

error: type mismatch; 
found : (java.awt.event.ActionEvent) => Unit 
required: java.awt.event.ActionListener 
    button.addActionListener{ e:ActionEvent => println("test") } 
             ^

Ciò è vero almeno con il compilatore Scala versione 2.7.6.final sul mio sistema. Sono in grado di ottenere ciò che voglio nel modo in stile Java di implementare esplicitamente un ActionListener anonimo.

button.addActionListener(new ActionListener() { 
    def actionPerformed(e:ActionEvent) { println("test") } 
}) 

Per quanto ho capito, Scala dovrebbe essere in grado di utilizzare anatra tipizzazione per rendere questo esplicito attuazione ActionListener inutili; quindi perché non funziona qui? Non ho quasi nessuna esperienza pratica di tipizzazione delle anatre a questo punto.

risposta

11

Duck-typing non ha nulla a che fare con il motivo che il codice non funziona. È perché il sistema di tipi Scala non fornisce la conversione implicita tra tipo di interfaccia e il tipo di funzione per impostazione predefinita. Tuttavia, se viene definita la seguente conversione implicita, il codice funziona correttamente.

implicit def toActionListener(f: ActionEvent => Unit) = new ActionListener { 
    def actionPerformed(e: ActionEvent) { f(e) } 
} 

Questa conversione implicita fornisce conversioni da (ActionEvent => Unit) a ActionListner.

+1

Non come fanboy, ma vale la pena notare che sia Groovy che le varie proposte di chiusura Java includevano conversioni implicite da tipi di funzione appropriati a interfacce a metodo singolo. Questo è molto conveniente per interfacce come Runnable o Comparable. In Scala, devi eseguire questa conversione manualmente o affidarti a librerie pimpate per farlo. –

+1

@Dave Sì ... se il tipo non corrisponde, esegui il cast automatico. Penso che dovrebbe essere ovvio perché Scala non ha scelto in questo modo. –

+0

Oh, certo. Ha senso solo per Groovy e Java perché non includono alcun buon metodo per estendere le librerie esistenti, quindi hanno bisogno di questa conversione automatica per rendere il lavoro con legacy Java non doloroso. Scala ha protettori per le librerie legacy e le nuove librerie dovrebbero essere (e vengono) scritte per favorire forme funzionali su interfacce a metodo singolo. –

4

Scala non è anatra. Ha una tipizzazione strutturale facoltativa ed esplicita, ma questo non ha nulla a che fare con il perché il tuo codice non funziona.

Il tuo codice non funziona, perché JButton.addActionListener si aspetta un argomento come ActionListener, non una funzione. Anche se scala fosse doppino, non si poteva semplicemente passare una funzione perché gli stessi metodi disponibili su un ActionListener non sono disponibili su una funzione.

Nota che l'articolo dice "Supponiamo per un momento felice di poter riscrivere Swing per sfruttare appieno la sintassi di Scala", cioè l'articolo non pretende di mostrare il codice effettivo che funziona.

Tuttavia scala ha il proprio pacchetto swing (scala.swing) che contiene classi che sono più "scalaish" da utilizzare rispetto ai loro equivalenti java.

+0

Ah, quella citazione dall'articolo è davvero pertinente. Ho avuto la sensazione di fare una domanda in pubblico era destinato a esporre alcuni errori di comprensione di lettura di base da parte mia ... Ancora, la tua risposta è informativa. Grazie. – PeterT

Problemi correlati