这是Scala' Phantom Type'演示显示compile-time checking of Rocket Launch configuration:
object RocketModule {
sealed trait NoFuel
sealed trait Fueled
sealed trait NoO2
sealed trait HasO2
final case class Rocket[Fuel, O2] private[RocketModule]()
def createRocket = Rocket[NoFuel, NoO2]()
def addFuel[O2](x : Rocket[NoFuel, O2]) = Rocket[Fueled, O2]()
def addO2[Fuel](x : Rocket[Fuel, NoO2]) = Rocket[Fuel, HasO2]()
def launch(x : Rocket[Fueled, HasO2]) = "blastoff"
implicit def toPiped[V] (value:V) = new {
def |>[R] (f : V => R) = f(value)
}
//Create a rocket, fuel it, add o2, then launch it
def test1 = createRocket |> addFuel |> addO2 |> launch
//This compiles just fine, too. It doesn't matter which order we put in the fuel and o2
def test2 = createRocket |> addO2 |> addFuel |> launch
//This won't compile - there's no fuel
def test3 = createRocket |> addO2 |> launch
// This won't compile either - there's no o2
def test4 = createRocket |> addFuel |> launch
// This won't compile because you can't add fuel twice
def test5 = createRocket |> addFuel |> addO2 |> addFuel |> launch
}
我试图将其转换为Java等价物。
package com.example;
public class RocketModule {
public static NoFuelNoO2Rocket createRocket() {return new NoFuelNoO2Rocket() {};}
public static void launch(HasFuelHasO2Rocket rocket) {System.out.println("Launch");}
private static NoFuelHasO2Rocket addO2(NoFuelNoO2Rocket rocket) {return rocket.addO2();}
private static HasFuelHasO2Rocket addO2(HasFuelNoO2Rocket rocket) {return rocket.addO2();}
private static HasFuelNoO2Rocket addFuel(NoFuelNoO2Rocket rocket) {return rocket.addFuel();}
private static HasFuelHasO2Rocket addFuel(NoFuelHasO2Rocket rocket) {return rocket.addFuel();}
public static void main(String args[]) {
//test1
launch(addFuel(addO2(createRocket())));
//test2
launch(addO2(addFuel(createRocket())));
//test3 - won't compile - no Fuel
//launch(addO2(createRocket()));
//test4 - won't compile - no O2
//launch(addFuel(createRocket()));
//test5 - won't compile - can't add fuel twice
//launch(addFuel(addO2(addFuel(createRocket()))));
}
}
class NoFuelNoO2Rocket {
public NoFuelHasO2Rocket addO2() {return new NoFuelHasO2Rocket();}
public HasFuelNoO2Rocket addFuel() {return new HasFuelNoO2Rocket();}
}
class HasFuelNoO2Rocket {
public HasFuelHasO2Rocket addO2() {return new HasFuelHasO2Rocket();}
}
class NoFuelHasO2Rocket {
public HasFuelHasO2Rocket addFuel() {return new HasFuelHasO2Rocket();}
}
class HasFuelHasO2Rocket {}
我的问题是:这是“幻影类型”的准确转换吗?在Java?
答案 0 :(得分:2)
您似乎可以直接将Scala示例翻译为Java:
interface Fueled {}
interface NoFuel {}
interface HasO2 {}
interface NoO2 {}
class Rocket<Fuel, O2> {}
public class PhantomJava {
public static Rocket<NoFuel, NoO2> createRocket() { return new Rocket<NoFuel, NoO2>(); }
public static void launch(Rocket<Fueled, HasO2> rocket) { System.out.println("Launch"); }
private static <Fuel> Rocket<Fuel, HasO2> addO2(Rocket<Fuel, NoO2> rocket) { return new Rocket<Fuel, HasO2>(); }
private static <O2> Rocket<Fueled, O2> addFuel(Rocket<NoFuel, O2> rocket) { return new Rocket<Fueled, O2>(); }
public static void main(String args[]) {
// test1
launch(addFuel(addO2(createRocket())));
// test2
launch(addO2(addFuel(createRocket())));
// test3 - won't compile - no Fuel
// launch(addO2(createRocket()));
// test4 - won't compile - no O2
// launch(addFuel(createRocket()));
// test5 - won't compile - can't add fuel twice
// launch(addFuel(addO2(addFuel(createRocket()))));
}
}
此外,您应该在Scala和Java代码中添加一些类型约束。
Scala的:
sealed trait FuelStatus
sealed trait NoFuel extends FuelStatus
sealed trait Fueled extends FuelStatus
sealed trait O2Status
sealed trait NoO2 extends O2Status
sealed trait HasO2 extends O2Status
final case class Rocket[Fuel <: FuelStatus, O2 <: O2Status] private[PhantomScala]()
def addFuel[O2 <: O2Status](x : Rocket[NoFuel, O2]) = Rocket[Fueled, O2]()
def addO2[Fuel <: FuelStatus](x : Rocket[Fuel, NoO2]) = Rocket[Fuel, HasO2]()
爪哇:
interface FuelStatus {}
interface Fueled extends FuelStatus {}
interface NoFuel extends FuelStatus {}
interface O2Status {}
interface HasO2 extends O2Status {}
interface NoO2 extends O2Status {}
class Rocket<Fuel extends FuelStatus, O2 extends O2Status> {}
...
private static <Fuel extends FuelStatus> Rocket<Fuel, HasO2> addO2(Rocket<Fuel, NoO2> rocket) { return new Rocket<Fuel, HasO2>(); }
private static <O2 extends O2Status> Rocket<Fueled, O2> addFuel(Rocket<NoFuel, O2> rocket) { return new Rocket<Fueled, O2>(); }