How do I disambiguate in Scala between methods with vararg and without

a 夏天 提交于 2019-12-28 02:07:14

问题


I'm trying to use the java jcommander library from Scala. The java JCommander class has multiple constructors:

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

I want to to call the first constructor that takes no varargs. I tried:

jCommander = new JCommander(cmdLineArgs)

I get the error:

error: ambiguous reference to overloaded definition,
both constructor JCommander in class JCommander of type (x$1: Any,x$2: <repeated...>[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)

I've also tried using a named parameter, but got the same result:

jCommander = new JCommander(`object` = cmdLineArgs)

How do I tell Scala I want to call the constructor that doesn't take varargs?

I'm using Scala 2.8.0.


回答1:


Sorry, I now realize this is a known interoperability problem with Java. See this question and the ticket. The only work around I know of is to create a small Java class just to disambiguate these calls.




回答2:


The only Scala solution to this problem that I know involves reflection.

Ambiguous Methods

Let's suppose we have a Java test class:

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; }
}

We can get access to the method via reflection directly:

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]

or we can use structural types (which use reflection under the hood) to achieve the same thing with less boilerplate:

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

Ambiguous Constructors

Our strategy has to differ because we don't actually have an object to begin with. Let's suppose we have the Java class

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; }
}

The structural types approach no longer works, but we can still use reflection:

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



回答3:


I think your easiest option is to have a Java class with a factory method to bridge the issue:

package com.beust.jcommander;

public class JCommanderFactory {
    public static createWithArgs(Object cmdLineArgs) {
        return new JCommander(cmdLineArgs);
    }
}

Alternatively you could use http://jewelcli.sourceforge.net/usage.html instead. JewelCli has an unambiguous factory method for the same purpose and also uses PICA (Proxied Interfaces Configured with Annotations) technique http://www.devx.com/Java/Article/42492/1954.

In fact I have an example of using JewelCLI with Scala here on Stack Overflow.




回答4:


The way to avoid this ambiguity is to force the compiler to pick the overload that takes more than one argument, using Scala's collection explosion syntax to pass in a singleton collection:

import java.util.stream.Stream
val stream = Stream.of(List(1):_*)



回答5:


You can call the constructor with varags, but pass an empty list of varags.

(Of course, if you know that constructing JCommander with empty varags will produce the same result as calling the overloaded constructor (or method) without vargs)

jCommander = new JCommander(cmdLineArgs, Nil: _*)



来源:https://stackoverflow.com/questions/3313929/how-do-i-disambiguate-in-scala-between-methods-with-vararg-and-without

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!