如何在 Java 中传递通过 Scala 中的包对象定义的隐式值
How to pass implicit vals defined through package objects from Scala in Java
我正在使用 Cats 库。在 Scala 中,代码如下所示:
import cats.Semigroupal
import cats.instances.option._
val r = Semigroupal.tuple2(Option(1), Option(2))
tuple2
定义为:
def tuple2[F[_], A0, A1](f0:F[A0], f1:F[A1])(implicit semigroupal: Semigroupal[F], invariant: Invariant[F]):F[(A0, A1)]
以下隐式值实际上作为 Semigroupal
和 Invariant
传递(通过 Scala 的 Intellij IDEA 插件检查):
package cats
package instances
trait OptionInstances ...
implicit val catsStdInstancesForOption: ...
如何通过 Java 代码在 tuple2
函数中传递 catsStdInstancesForOption
?
Semigroupal$.MODULE$.tuple2(
Option.apply(1), Option.apply(2),
...,// and here?
... //here
);
如果需要,对 Cats 库的依赖:
<cats.core.version>1.5.0</cats.core.version>
...
<!-- https://mvnrepository.com/artifact/org.typelevel/cats-core -->
<dependency>
<groupId>org.typelevel</groupId>
<artifactId>cats-core_2.12</artifactId>
<version>${cats.core.version}</version>
</dependency>
从 Java 引用包对象内部定义的 Scala 对象是一件痛苦的事情,据我所知,这没有充分的理由——这完全是因为编译器决定破坏名称的方式 (例如,您不能直接从 Java).
引用 cats.instances.package$option$
我以前也想做这种事情,我找到的最好的解决方案是这样的:
import cats.Apply;
import cats.Semigroupal$;
import cats.instances.OptionInstances;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import scala.Option;
import scala.Tuple2;
public class Test {
public static Apply<Option> getOptionInstance() {
try {
Class<?> cls = Class.forName("cats.instances.package$option$");
Field f = cls.getField("MODULE$");
Method m = f.getType().getMethod("catsStdInstancesForOption");
return (Apply<Option>) m.invoke(f.get(null));
} catch (Exception e) {
// Shouldn't happen but do something here anyway.
return null;
}
}
public static void main(String[] args) {
Apply<Option> optionInstance = getOptionInstance();
Option<Tuple2<Integer, Integer>> pair = Semigroupal$.MODULE$.tuple2(
Option.apply(1),
Option.apply(2),
optionInstance,
optionInstance
);
System.out.println(pair);
}
}
这很糟糕,但至少反射和投射捆绑在一个地方。
如果您有很多需要使用 Java 的实例,您可以从 getOptionInstance
中抽象出一些逻辑来减少重复,但它仍然不会很有趣.如果你可以在 Scala 端编写一些实用程序代码以使用 Java,那么制作一个更 Java 友好的 cats.instances
并不难——只是不要使用 package对象等(对于它的价值,我希望 Cats 在其开发过程中更多地关注 Java-友好性,但据我所知,没有其他人关心这一点。)
我正在使用 Cats 库。在 Scala 中,代码如下所示:
import cats.Semigroupal
import cats.instances.option._
val r = Semigroupal.tuple2(Option(1), Option(2))
tuple2
定义为:
def tuple2[F[_], A0, A1](f0:F[A0], f1:F[A1])(implicit semigroupal: Semigroupal[F], invariant: Invariant[F]):F[(A0, A1)]
以下隐式值实际上作为 Semigroupal
和 Invariant
传递(通过 Scala 的 Intellij IDEA 插件检查):
package cats
package instances
trait OptionInstances ...
implicit val catsStdInstancesForOption: ...
如何通过 Java 代码在 tuple2
函数中传递 catsStdInstancesForOption
?
Semigroupal$.MODULE$.tuple2(
Option.apply(1), Option.apply(2),
...,// and here?
... //here
);
如果需要,对 Cats 库的依赖:
<cats.core.version>1.5.0</cats.core.version>
...
<!-- https://mvnrepository.com/artifact/org.typelevel/cats-core -->
<dependency>
<groupId>org.typelevel</groupId>
<artifactId>cats-core_2.12</artifactId>
<version>${cats.core.version}</version>
</dependency>
从 Java 引用包对象内部定义的 Scala 对象是一件痛苦的事情,据我所知,这没有充分的理由——这完全是因为编译器决定破坏名称的方式 (例如,您不能直接从 Java).
引用cats.instances.package$option$
我以前也想做这种事情,我找到的最好的解决方案是这样的:
import cats.Apply;
import cats.Semigroupal$;
import cats.instances.OptionInstances;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import scala.Option;
import scala.Tuple2;
public class Test {
public static Apply<Option> getOptionInstance() {
try {
Class<?> cls = Class.forName("cats.instances.package$option$");
Field f = cls.getField("MODULE$");
Method m = f.getType().getMethod("catsStdInstancesForOption");
return (Apply<Option>) m.invoke(f.get(null));
} catch (Exception e) {
// Shouldn't happen but do something here anyway.
return null;
}
}
public static void main(String[] args) {
Apply<Option> optionInstance = getOptionInstance();
Option<Tuple2<Integer, Integer>> pair = Semigroupal$.MODULE$.tuple2(
Option.apply(1),
Option.apply(2),
optionInstance,
optionInstance
);
System.out.println(pair);
}
}
这很糟糕,但至少反射和投射捆绑在一个地方。
如果您有很多需要使用 Java 的实例,您可以从 getOptionInstance
中抽象出一些逻辑来减少重复,但它仍然不会很有趣.如果你可以在 Scala 端编写一些实用程序代码以使用 Java,那么制作一个更 Java 友好的 cats.instances
并不难——只是不要使用 package对象等(对于它的价值,我希望 Cats 在其开发过程中更多地关注 Java-友好性,但据我所知,没有其他人关心这一点。)