Scala/Java interoperability: How to deal with options containing Int/Long (primitive types)?

倖福魔咒の 提交于 2019-12-23 11:55:21

问题


Given a service in Scala:

class ScalaService {
  def process1(s: Option[String], i: Option[Int]) {
    println("1: " + s + ", " + i)
  }
}

which is to be used from Java:

public class Java {
    public static void main(String[] args) {
        ScalaService service = new ScalaService();

        // This works, but it's confusing
        {
            scala.Option<String> so = scala.Option.apply("Hello");
            scala.Option<Object> io = scala.Option.apply((Object) 10);
            service.process1(so, io);
        }

        // Would be OK, but not really nice
        {
            scala.Option<Object> so = scala.Option.apply((Object) "Hello");
            scala.Option<Object> io = scala.Option.apply((Object) 10);
            service.process1(so, io); // Does not compile
        }

        // The preferred way
        {
            scala.Option<String> so = scala.Option.apply("Hello");
            scala.Option<Integer> io = scala.Option.apply(10);
            service.process1(so, io); // Does not compile
        }

    }
}

I'd like to avoid to treat primitive and non-primitive types in a different way.

So I tried to get around this by adding another method:

def process2(s: Option[String], i: Option[java.lang.Integer]) {
  print("2: ")
  process1(s, i.map(v => v.toInt))
}

but this requires a different name for the method. As this could be confusing from the caller's perspective, are there any other possibilities?

I'm using Scala 2.10.1, and Java 1.6


回答1:


The method signature would be a bit confusing as well, but you could use pattern matching to handle the various types - something like:

class ScalaService {
  def process1(s: Option[String], i: Option[Any]) {
    i match {
      case Some(i2:Int) => processInternal(s, Some(i2))
      case Some(i2:java.lang.Integer) => processInternal(s, Some(i2.intValue))
      case _ => processInternal(s, None) // or throw exception if you prefer
    }

    def processInternal(s:Option[String], i:Option[Int]) { 
      println("1: " + s + ", " + i) 
    }
  }
}

Also, I am not sure about calling from java, but perhaps an implicit conversion from java.lang.Integer to Int might also work?




回答2:


The solution I am going to test is to use a DummyImplicit, so I can have the same method name for both the Scala and the Java method:

class ScalaService {
  // To be called from Scala
  def process(s: Option[String], i: Option[Int])(implicit d: DummyImplicit) {
    println("1: " + s + ", " + i)
  }

  // To be called from Java
  def process(s: Option[String], i: Option[java.lang.Integer]) {
    print("2: ")
    process(s, i.map(v => v.toInt))
  }

to be used from Scala like this:

object ScalaService extends App {
  val s = new ScalaService()
  s.process(Some("Hello"), Some(123))
}

and from Java:

public class Java {
    public static void main(String[] args) {
        ScalaService service = new ScalaService();

        {
            scala.Option<String> so = scala.Option.apply("Hello");
            scala.Option<Integer> io = scala.Option.apply(10);
            service.process(so, io);
        }
    }

}


来源:https://stackoverflow.com/questions/17071061/scala-java-interoperability-how-to-deal-with-options-containing-int-long-primi

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