Как я могу устранить ошибку в Scala между методами с vararg и без

Я пытаюсь использовать библиотеку java jcommander из Scala. Класс java JCommander имеет несколько конструкторов:

public JCommander(Object object) public JCommander(Object object, ResourceBundle bundle, String... args) public JCommander(Object object, String... args) 

Я хочу вызвать первый конструктор, который не принимает varargs. Я пытался:

 jCommander = new JCommander(cmdLineArgs) 

Я получаю сообщение об ошибке:

 error: ambiguous reference to overloaded definition, both constructor JCommander in class JCommander of type (x$1: Any,x$2: [java.lang.String])com.beust.jcommander.JCommander and constructor JCommander in class JCommander of type (x$1: Any)com.beust.jcommander.JCommander match argument types (com.lasic.CommandLineArgs) and expected result type com.beust.jcommander.JCommander jCommander = new JCommander(cmdLineArgs) 

Я также попытался использовать именованный параметр, но получил тот же результат:

 jCommander = new JCommander(`object` = cmdLineArgs) 

Как сообщить Scala, что я хочу вызвать конструктор, который не принимает varargs?

Я использую Scala 2.8.0.

Извините, теперь я понимаю, что это известная проблема совместимости с Java. См. Этот вопрос и билет . Единственная работа, о которой я знаю, – создать небольшой Java-class, чтобы просто устранить эти вызовы.

Единственное решение Scala для этой проблемы, которое я знаю, связано с размышлением.

Неоднозначные методы

Предположим, у нас есть тестовый class Java:

 public class Ambig { public Ambig() {} public String say(Object o) { return o.toString(); } public String say(Object o, String... ss) { return o.toString()+ss.length; } } 

Мы можем напрямую получить доступ к методу посредством отражения:

 val ambig = new Ambig val methods = ambig.getClass.getMethods.filter(_.getName == "say") val wanted = methods.find(_.getParameterTypes.length == 1).get wanted.invoke(ambig, Some(5)).asInstanceOf[String] 

или мы можем использовать структурные типы (которые используют reflection под капотом) для достижения того же самого результата с меньшим количеством шаблонов:

 def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o) sayer(new Ambig, Some(5)) 

Неоднозначные конструкторы

Наша страtagsя должна отличаться, потому что на самом деле у нас нет объекта для начала. Предположим, что у нас есть class Java

 public class Ambig2 { public final String say; public Ambig2(Object o) { say = o.toString(); } public Ambig2(Object o, String... ss) { say = o.toString()+ss.length; } } 

Подход структурных типов больше не работает, но мы все еще можем использовать reflection:

 val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1) val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2] ambig.say // Some(5) 

Я думаю, что ваш самый простой вариант – иметь class Java с заводским методом для устранения проблемы:

 package com.beust.jcommander; public class JCommanderFactory { public static createWithArgs(Object cmdLineArgs) { return new JCommander(cmdLineArgs); } } 

Вместо этого вы можете использовать http://jewelcli.sourceforge.net/usage.html . JewelCli имеет однозначный заводский метод для этой же цели, а также использует технику PICA (Proxied Interfaces Configured with Annotations) http://www.devx.com/Java/Article/42492/1954 .

На самом деле у меня есть пример использования JewelCLI с Scala здесь в Stack Overflow .

Способ избежать этой двусмысленности заключается в том, чтобы заставить компилятор выбрать перегрузку, которая принимает более одного аргумента, используя синтаксис взрыва коллекции Scala для передачи в одноэлементной коллекции:

 import java.util.stream.Stream val stream = Stream.of(List(1):_*) 
Давайте будем гением компьютера.