我有一个实例scala.collection.immutable.List
,我想调用map
的方法就可以了,但是从Java。
我需要提供一个CanBuildFrom
。
我注意到,很多Scala集合同伴对象包含隐含CanBuildFrom
实例,但我不能工作了,我需要用哪一个。
这是我的Java代码:
Function1<WeatherData, BigDecimal> mapper = new AbstractFunction1<WeatherData, BigDecimal>(){
@Override
public BigDecimal apply(WeatherData data) {
return data.getTemps().reduce(adder).divide(new BigDecimal(data.getTemps().size()));
}
};
scala.collection.immutable.List<WeatherData> data = ...
data.map(mapper, ???);
我应该怎么过的CanBuildFrom(第二个参数?)
PS使用Scala的2.10-M5
实际上,你可以得到正确的Java中的类型,而太过计较:
import scala.collection.Traversable;
import scala.collection.generic.CanBuildFrom;
import scala.collection.immutable.List;
import scala.collection.mutable.Builder;
import scala.runtime.AbstractFunction1;
public class ScalaMapTest {
public static List<Integer> parseInts(List<String> xs) {
final CanBuildFrom<List<?>, Integer, List<Integer>> builder =
List.<Integer>canBuildFrom();
return xs.map(
new AbstractFunction1<String, Integer>() {
public Integer apply(String s) {
return Integer.parseInt(s);
}
},
new CanBuildFrom<Traversable<String>, Integer, List<Integer>>() {
public Builder<Integer, List<Integer>> apply() {
return builder.apply();
}
public Builder<Integer, List<Integer>> apply(Traversable<String> from) {
return builder.apply(from.toList());
}
}
);
}
}
这是罪还是丑陋,但它的工作原理。 问题是在通配符CanBuildFrom
你从一开始canBuildFrom
on方法List
对象,但幸运的是,你可以创建自己的CanBuildFrom
用正确类型的包装。
如果你想知道的代码做什么scalac然后问它。 ;)
这是可能的或者scalac -Xprint:typer <file>
或在2.10新反射API:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> reify{List(1,2,3).map(_+1)}
res0: reflect.runtime.universe.Expr[List[Int]] = Expr[List[Int]](immutable.this.List.apply(1, 2, 3).map(((x$1) => x$1.$plus(1)))(immutable.this.List.canBuildFrom))
因此,调用map
这个CanBuildFrom
和一切工作正常。 难道是真的吗? 不,不! 问题是,Java编译器是愚蠢的,推断出预期的参数map
。 那么该怎么办? 我认为,唯一的办法就是创建所需的值,并将它们转换成死亡。 最后,混合一些SuppressWarnings-Annotations
在和代码应该正常工作。 ;)
这是我想出了:
import scala.Function1;
import scala.collection.generic.CanBuildFrom;
import scala.collection.immutable.List;
import scala.collection.immutable.List$;
import scala.runtime.AbstractFunction1;
public class JTest {
@SuppressWarnings({"unchecked", "rawtypes"})
public static void main(final String... args) {
final List<Integer> xxx = (List) List$.MODULE$.apply(Predef.wrapIntArray(new int[] {1,2,3}));
System.out.println(xxx);
System.out.println(Test.sum(1, 2));
final Abc abc = new Abc();
System.out.println(abc.hello("simon"));
final List<Integer> xs = (List) Test.xs();
final Function1<Integer, String> mapper = new AbstractFunction1<Integer, String>() {
@Override
public String apply(final Integer i) {
return String.valueOf(i);
}
};
final CanBuildFrom<List<Integer>, String, List<String>> cbf =
(CanBuildFrom) List.<Integer>canBuildFrom();
final List<String> ys = xs.<String, List<String>>map(mapper, cbf);
System.out.println(ys);
}
}
名单:
object Test {
def xs = List(1,2,3)
}
我认为,最好的办法是不要从Java使用Scala代码。 它看起来丑陋。 至少,它包在一些辅助类,这样的人谁看到这个代码不想想他的视网膜酸攻击。
顺便说一句,有时你必须看看字节码,了解如何scalac创造价值。 如果你想创建一个列表斯卡拉就是Java,你必须反编译的代码javap -c -s -l -verbose -private <classfile>
:
0: aload_0
1: invokespecial #20; //Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #22; //Field MODULE$:LX$;
8: aload_0
9: getstatic #27; //Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$;
12: getstatic #32; //Field scala/Predef$.MODULE$:Lscala/Predef$;
15: iconst_3
16: newarray int
18: dup
19: iconst_0
20: iconst_1
21: iastore
22: dup
23: iconst_1
24: iconst_2
25: iastore
26: dup
27: iconst_2
28: iconst_3
29: iastore
30: invokevirtual #38; //Method scala/LowPriorityImplicits.wrapIntArray:([I)Lscala/collection/mutable/WrappedArray;
33: invokevirtual #42; //Method scala/collection/immutable/List$.apply:(Lscala/collection/Seq;)Lscala/collection/immutable/List;
36: new #44; //class X$$anonfun$1
或在更可读的Java代码:
@SuppressWarnings({"unchecked", "rawtypes"})
final List<Integer> xs = (List) List$.MODULE$.apply(Predef.wrapIntArray(new int[] {1,2,3}));