Как объявить метод scala, чтобы его можно было вызывать из Java с использованием стиля varargs - PullRequest
9 голосов
/ 22 июня 2010

У меня есть 2 простых метода в классе библиотеки scala:

class Foo {
  def bar(args : String*) : Unit = println("Foo.bar with: " + args)
  def bar(args : Array[String]) : Unit = bar(args.toSeq : _*)
}

Все это прекрасно компилируется.Затем я помещаю это в библиотеку foo.jar и пытаюсь скомпилировать следующий фрагмент Java:

import Foo
public class Test {

    public static void main(String[] args) {
        Foo foo = new Foo();
        foo.bar("Hello", "World"); //DOES NOT COMPILE
    }
}

. Я могу заменить ошибочную строку на:

foo.bar(new String[] { "Hello", "World" }); //OK

Но, похоже, этопобедить точку.Как я могу вызвать его из Java, используя Java-подобный синтаксису varargs?

Ответы [ 4 ]

3 голосов
/ 24 июня 2010

В 2.8 (не знаю о 2.7), если вы переопределяете метод varargs из родительского объекта Java или реализуете метод varargs из интерфейса Java, то компилятор Scala сгенерирует два метода: один для Scala, другой для Java.Java - как вы сами можете убедиться, проверив байт-код - просто берет массив varargs и упаковывает его, затем передает WrappedArray в версию Scala, которая ожидает Seq.

Если есть способзаставить компилятор сгенерировать форвардер при других обстоятельствах, я не знаю об этом.Я сомневаюсь, что это существует.Похоже, предоставление способа запроса об этом (я думаю, аннотация) было бы разумным запросом на усовершенствование.

1 голос
/ 22 мая 2012

См. ответ на этот вопрос :

Вы можете использовать @annotation.varargs, чтобы указать scala генерировать оба метода:

class Foo {
  @annotation.varargs def bar(args : String*) : Unit = println("Foo.bar with: " + args)
  def bar(args : Array[String]) : Unit = bar(args.toSeq : _*)
}
1 голос
/ 22 июня 2010

Не совсем уверен, но я думаю, что varargs в Scala использует Sequence и отличается от реализации Java. Я думаю, что самый простой способ выполнить то, что вы хотите, это создать подкласс класса Foo Scala в Java и добавить метод bar, который принимает Java vararg, т.е.

public class JavaFoo extends Foo {
    public void bar(String... args) {
         super.bar(args)
    }
}

Затем можно вызвать метод JavaFoo vararg с использованием синтаксиса vararg в Java.

Надеюсь, это поможет:)

0 голосов
/ 29 декабря 2011

Несмотря на полезный совет об использовании Java-интерфейса для обеспечения «совместимости» компилятора Scala, я просто не мог заставить свой код работать. В конце концов меня осенило, что методы были объявлены для объекта Scala , что означает, что они на самом деле являются статическими, и вы не можете указать статические методы в интерфейсе, поэтому компилятор просто игнорировал тот факт, что Объект реализовал интерфейс. К счастью для меня, есть обходной путь. Вместо того, чтобы вызывать статический метод непосредственно из Java, вот так:

CLASS.method(x,y,z)

Вы должны назвать это так:

CLASS$.MODULE$.method(x,y,z)

Это означает, что вы фактически обращаетесь к одноэлементному объекту как к экземпляру, на который ссылается статическое поле, и, поскольку он является экземпляром и реализует интерфейс Java, там компилятор выполняет свою работу должным образом и реализует метод varargs, так что Java может вызывать его как varargs.

Лично я считаю, что это следует рассматривать как ошибку компилятора Scala.

...