Java 如何处理 Scala 类型中的协变性
How to deal with Covariancy in Scala types from Java
在我们的 Scala 项目中,我们使用包含协变类型参数的类型来传达决策。
sealed trait ArbiterResponse[+Tasks]
object Reject extends ArbiterResponse[Nothing]
trait Proceed[Tasks] extends ArbiterResponse[Tasks]
object Proceed extends Proceed[Nothing]
case class ProceedConditionally[Tasks](tasks : Tasks) extends Proceed[Tasks]
当从 Java 使用它时,我收到一个错误,指出 ArbiterResponse<SomeTask>
无法转换为 Reject$
in:
final ArbiterResponse<SomeTask> response = ???
if (task instanceof Reject$) { ... }
error: incompatible types: ArbiterResponse cannot be converted to Reject$
我该如何解决这个问题?我想这是因为 Java 编译器不知道 co-/contravariance。我通过添加描述 ArbiterResponse
响应类型的标志来解决这个问题。但我不太喜欢这个解决方案,因为它是一些手动的、容易出错的工作。谁有更好的主意?
sealed trait ArbiterResponse[+Tasks] {
def isRejected: Boolean
def isProceed: Boolean
def isProceedConditionally: Boolean
}
object Reject extends ArbiterResponse[Nothing] {
def isRejected = true
def isProceed = false
def isProceedConditionally = false
}
trait Proceed[Tasks] extends ArbiterResponse[Tasks] {
def isRejected = false
def isProceed = true
def isProceedConditionally = false
}
object Proceed extends Proceed[Nothing]
case class ProceedConditionally[Tasks](tasks : Tasks) extends Proceed[Tasks] {
override def isProceedConditionally = true
}
在大多数情况下从 java 调用 scala 代码是相当棘手的。但无论如何,如果你想通过类型转换的方式,那么你可以这样做:
for (Object response : Arrays.asList(new ProceedConditionally("asdf"), Reject$.MODULE$)) {
if(Reject$.class.isInstance(response)){
Reject$ cast = Reject$.class.cast(response);
System.out.println(cast);
}else if(Proceed.class.isInstance(response)){
System.out.println("Proceed");
}else{
System.out.println("Nothing: "+response.getClass());
}
}
打印
Proceed
prac.Reject$@266474c2
但它可能很快就会因不同的 Scala 版本而崩溃,或者很难让它正确。一种方法可能是通过访问者模式方式。不完全令人满意,但可能会有所帮助
sealed trait ArbiterResponse[+Tasks]{
def doSomething
}
object Reject extends ArbiterResponse[Nothing]{
def doSomething = ???
}
trait Proceed[Tasks] extends ArbiterResponse[Tasks]
object Proceed extends Proceed[Nothing]{
def doSomething = ???
}
case class ProceedConditionally[Tasks](tasks : Tasks) extends Proceed[Tasks]{
def doSomething = println(tasks)
}
在我们的 Scala 项目中,我们使用包含协变类型参数的类型来传达决策。
sealed trait ArbiterResponse[+Tasks]
object Reject extends ArbiterResponse[Nothing]
trait Proceed[Tasks] extends ArbiterResponse[Tasks]
object Proceed extends Proceed[Nothing]
case class ProceedConditionally[Tasks](tasks : Tasks) extends Proceed[Tasks]
当从 Java 使用它时,我收到一个错误,指出 ArbiterResponse<SomeTask>
无法转换为 Reject$
in:
final ArbiterResponse<SomeTask> response = ???
if (task instanceof Reject$) { ... }
error: incompatible types: ArbiterResponse cannot be converted to Reject$
我该如何解决这个问题?我想这是因为 Java 编译器不知道 co-/contravariance。我通过添加描述 ArbiterResponse
响应类型的标志来解决这个问题。但我不太喜欢这个解决方案,因为它是一些手动的、容易出错的工作。谁有更好的主意?
sealed trait ArbiterResponse[+Tasks] {
def isRejected: Boolean
def isProceed: Boolean
def isProceedConditionally: Boolean
}
object Reject extends ArbiterResponse[Nothing] {
def isRejected = true
def isProceed = false
def isProceedConditionally = false
}
trait Proceed[Tasks] extends ArbiterResponse[Tasks] {
def isRejected = false
def isProceed = true
def isProceedConditionally = false
}
object Proceed extends Proceed[Nothing]
case class ProceedConditionally[Tasks](tasks : Tasks) extends Proceed[Tasks] {
override def isProceedConditionally = true
}
在大多数情况下从 java 调用 scala 代码是相当棘手的。但无论如何,如果你想通过类型转换的方式,那么你可以这样做:
for (Object response : Arrays.asList(new ProceedConditionally("asdf"), Reject$.MODULE$)) {
if(Reject$.class.isInstance(response)){
Reject$ cast = Reject$.class.cast(response);
System.out.println(cast);
}else if(Proceed.class.isInstance(response)){
System.out.println("Proceed");
}else{
System.out.println("Nothing: "+response.getClass());
}
}
打印
Proceed
prac.Reject$@266474c2
但它可能很快就会因不同的 Scala 版本而崩溃,或者很难让它正确。一种方法可能是通过访问者模式方式。不完全令人满意,但可能会有所帮助
sealed trait ArbiterResponse[+Tasks]{
def doSomething
}
object Reject extends ArbiterResponse[Nothing]{
def doSomething = ???
}
trait Proceed[Tasks] extends ArbiterResponse[Tasks]
object Proceed extends Proceed[Nothing]{
def doSomething = ???
}
case class ProceedConditionally[Tasks](tasks : Tasks) extends Proceed[Tasks]{
def doSomething = println(tasks)
}