2012-12-21 104 views
1

我想表达以下所有Scala代码的Java中:调用scala.Function.tupled()从Java

object TupleDemo { 
    val tuple = (3, "Hello, world! ") 

    /** @return str replicated x times */ 
    def foo(x: Int, str: String) = str * x 

    val tupledFoo1 = (foo _).tupled // partially applied function 

    val tupledFoo2 = Function.tupled(foo _) // desugared syntax for same partially applied function 
} 

object TupleDemoApp extends App { 
    import TupleDemo._ 

    println(tupledFoo1(tuple)) // Hello, world! Hello, world! Hello, world! 
    println(tupledFoo2(tuple)) // Hello, world! Hello, world! Hello, world! 
} 

这是不亚于我能想出了Java相当于:

import scala.Function1; 
import scala.Function2; 
import scala.Tuple2; 
import scala.collection.immutable.WrappedString; 
import scala.runtime.AbstractFunction2; 

public class JavaTupleDemo { 
    /** @return str replicated x times */ 
    static final Function2<Integer, String, String> foo = new AbstractFunction2<Integer, String, String>() { 
     public String apply(Integer x, String str) { 
      return new WrappedString(str).$times(x); 
     } 

     // perhaps the types for this method are incorrect? 
     public Function1<Tuple2<Integer, String>, String> tupled(Tuple2 tuple2) { 
      return null; // what to write here instead of null? 
     } 
    }; 

    public static void main(String[] args) { 
     // works: Invoke tupled function defined in Scala from Java using Tuple2 defined in Java 
     Tuple2<Object, String> tuple = new Tuple2<Object, String>(3, "Hello, World! "); 
     System.out.println(TupleDemo.tupledFoo1().apply(tuple)); 

     // works: Invoke regular function defined in Java from Java 
     System.out.println(JavaTupleDemo.foo.apply(3, "Hello, planet! ")); 

     // stumped: Invoke tupled function defined in Java from Java using both the Scala and the Java Tuple2 instances 
    } 
} 

回答

3

tupledFunction2实现的(因此AbstractFunction2),所以没有必要把它定义在这里,你可以这样写:

import scala.Function; 
import scala.Function2; 
import scala.Tuple2; 
import scala.collection.immutable.WrappedString; 
import scala.runtime.AbstractFunction2; 

public class JavaTupleDemo { 
    static final Function2<Integer, String, String> foo = 
    new AbstractFunction2<Integer, String, String>() { 
     public String apply(Integer x, String str) { 
     return new WrappedString(str).$times(x); 
     } 
    }; 

    public static void main(String[] args) { 
    Tuple2<Integer, String> tuple = 
     new Tuple2<Integer, String>(3, "Hello, World! "); 

    System.out.println(JavaTupleDemo.foo.tupled().apply(tuple)); 
    System.out.println(Function.tupled(JavaTupleDemo.foo).apply(tuple)); 
    } 
} 

请注意,我们需要编写foo.tupled(),因为Java认为这是一种方法,并且在这两种情况下我们都得到一个Function1,所以我们必须编写.apply(tuple),否则这基本上与Scala版本相同。


为了解决有关获取的类型为Object元组中的Integer你的问题:处理这个最简单的方法(假设你不能或不想使它成为Integer明确的斯卡拉侧)可能是以下几点:

Tuple2<Object, String> scalaTuple = TupleDemo.tuple(); 

Tuple2<Integer, String> tuple = new Tuple2<Integer, String>(
    (Integer) scalaTuple._1(), 
    scalaTuple._2() 
); 

也就是说,只取元组分开,铸就Integer,并把它重新走到一起。

+0

我非常亲密,但不能完全到达那里。谢谢! –

+0

元组的Scala版本对于Java而言表现为Tuple2 ,但元组的Java版本必须是Tuple2 。不可能从一个转换到另一个,所以我不能将代码的最后两行插入我的代码中。 –

0

特拉维斯布朗回答的问题是,他没有包括所有的代码。这是完整的代码,它不会编译。

import scala.Function; 
import scala.Function2; 
import scala.Tuple2; 
import scala.collection.immutable.WrappedString; 
import scala.runtime.AbstractFunction2; 

public class JavaTupleDemo { 
    /** tupled() is implemented in Function2 (and therefore in AbstractFunction2) 
    * @return str replicated x times */ 
    static final Function2<Integer, String, String> foo = new AbstractFunction2<Integer, String, String>() { 
     public String apply(Integer x, String str) { 
      return new WrappedString(str).$times(x); 
     } 
    }; 

    public static void main(String[] args) { 
     // Invoke tupled function defined in Scala from Java using Tuple2 defined in Java 
     Tuple2<Object, String> tuple = new Tuple2<Object, String>(3, "Hello, World! "); 
     System.out.println(TupleDemo.tupledFoo1().apply(tuple)); 

     // Invoke regular function defined in Java from Java 
     System.out.println(JavaTupleDemo.foo.apply(3, "Hello, planet! ")); 

     // Invoke tupled function defined in Java from Java using both the Scala and the Java Tuple2 instances 
     System.out.println(JavaTupleDemo.foo.tupled().apply(tuple)); 
     System.out.println(Function.tupled(JavaTupleDemo.foo).apply(tuple)); 
    } 
} 

错误消息是:

error: method apply in interface Function1<T1,R> cannot be applied to given types; 
required: Tuple2<Integer,String> 
found: Tuple2<Object,String> 
reason: actual argument Tuple2<Object,String> cannot be converted to Tuple2<Integer,String> by method invocation conversion 
where T1,R are type-variables: 
T1 extends Object declared in interface Function1 
R extends Object declared in interface Function1 

你不能简单地投下元组到Tuple2 <整数,字符串>。如果您尝试以下方法:

System.out.println(JavaTupleDemo.foo.tupled().apply((Tuple2<Integer, String>)tuple)); 
System.out.println(Function.tupled(JavaTupleDemo.foo).apply((Tuple2<Integer, String>)tuple)); 

的错误信息是:

error: inconvertible types 
required: Tuple2<Integer,String> 
found: Tuple2<Object,String> 

,使这个编译唯一的办法就是做真正讨厌的事情 - 第一投的元组对象,然后到Tuple2 < Integer,String>:

System.out.println(JavaTupleDemo.foo.tupled().apply((Tuple2<Integer, String>)((Object)javaTuple))); 
System.out.println(Function.tupled(JavaTupleDemo.foo).apply((Tuple2<Integer, String>)((Object)javaTuple))); 

有没有更好的方法来做到这一点?