2014-11-21 15 views
13

Scala offre @varargs annotation che genera un metodo di inoltro Java varargs, che permette di scrivere qualcosa del genere:astratti metodi e l'annotazione varargs

import scala.annotation.varargs 

class Foo { 
    @varargs def foo(args: String*): Unit = { 
    args.foreach(println) 
    } 
} 

E poi chiamare questo metodo da Java senza la necessità di creare un scala.Seq:

Foo foo = new Foo(); 
foo.foo("a", "b"); 

che è piuttosto bello.

Purtroppo la parte di inoltro non sembra accadere quando il metodo è astratto:

trait Bar { 
    @varargs def bar(args: String*): Unit 
} 

class Baz extends Bar { 
    def bar(args: String*): Unit = { 
    args.foreach(println) 
    } 
} 

Ora, se abbiamo questo codice Java:

Bar bar = new Baz(); 
bar.bar("a", "b"); 

Otteniamo questa eccezione (in fase di esecuzione) :

java.lang.AbstractMethodError: Baz.bar([Ljava/lang/String;)V 

possiamo confermare il problema con javap:

public interface Bar { 
    public abstract void bar(java.lang.String...); 
    public abstract void bar(scala.collection.Seq<java.lang.String>); 
} 

public class Baz implements Bar { 
    public void bar(scala.collection.Seq<java.lang.String>); 
    public Baz(); 
} 

Quindi, lo spedizioniere sicuramente non viene implementato.

Mettere l'annotazione su entrambi bar metodi fallisce la compilazione:

A method with a varargs annotation produces a forwarder method with the same 
signature (args: Array[String])Unit as an existing method. 

E naturalmente mettere l'annotazione solo sul bar in Baz significa che non possiamo usare solleva da un'istanza Bar.

Sembra che debba essere un bug, ma sembra anche estremamente facile da eseguire, e non vedo nulla nel tracker del problema. Sto usando correttamente @varargs? Se è così, c'è una soluzione che farebbe fare ciò che ti aspetteresti qui?

+0

Ops. Mi sembra un altro bug.Grazie a una soluzione "jugaad" per l'interoperabilità. Perbacco! quanti altri stanno mentendo lì? – Jatin

+0

Sembra un insetto. Prova a inviare un nuovo bug al tracker dei problemi. – Luminous

risposta

2

Non so Scala, ma in Java varargs è solo un array.

Così in Java che funzionerà in questo modo, con un avvertimento:

package tests.StackOverflow.q27052394; 

import java.util.Arrays; 

public class Runner { 

    public interface Bar { 
     public abstract void bar(java.lang.String ... ss); 
    } 

    public static class Baz implements Bar { 
     public void bar(java.lang.String[] array) { 
      System.out.println(Arrays.toString(array)); 
     } 
    } 

    public static void main(String[] args) { 

     Bar b = new Baz(); 

     b.bar("hello", "world"); 

    } 

} 

Può essere, se si può ingannare Scala allo stesso modo, riuscirete a superare il bug.

+0

Aggiunta di un metodo 'def bar (args: Array [String]): Unit = bar (args: _ *)' a 'Baz' sembra funzionare (anche se non è molto piacevole). –

1

Un modo per ottenere ciò che si desidera è di definire l'interfaccia in Java come segue

interface Bar { 
    public void bar(String... args); 
} 

e quindi per definire l'attuazione normalmente in Scala come segue

class Baz extends Bar { 
    def bar(args: String*): Unit = { 
    args.foreach(println) 
    } 
} 

Scala compilatore riconoscerà che ha bisogno di generare un metodo di stile vargs e genererà sia vararg che implementazione Seq.

uscita javap è come ci si aspetterebbe

public class Baz implements Bar { 
    public void bar(scala.collection.Seq<java.lang.String>); 
    public void bar(java.lang.String[]); 
    public Baz(); 
} 

interface Bar { 
    public abstract void bar(java.lang.String...); 
}