幻影类型是自定义类型的类型参数,但在该类型的任何值构造器中都没有用到。
这有点抽象,来看一个例子:
pub type Length(unit) {
Length(amount: Float)
}
在这个例子中,unit类型参数没有用在Length值构造器中,所以unit是一个幻影类型。
这个未使用的类型参数可能看起来没什么用,但可以用来进一步限制Length值的使用方式。
例如,我们可以有一个函数double,它把长度翻倍。它可以处理任何单位的长度,所以这个类型参数是一个泛型类型变量。
// This function accepts all Length values
pub fn double(length: Length(unit)) -> Length(unit) {
Length(length.amount *. 2.0)
}
我们还可以有一个函数add_inch,它只在长度以英寸为单位时有效。
// A unit type for inches. It is never constructed so we don't
// define any constructors for it.
pub type Inches
pub fn add_inch(length: Length(Inches)) -> Length(Inches) {
Length(length.amount +. 1.0)
}
add_inch函数不会接受其他单位参数的长度,这里借助幻影类型来确保只使用正确的单位。
也可以写一个函数,通过为两个长度值使用同一个类型变量,来确保它们具有相同的单位。
pub fn add(a: Length(unit), b: Length(unit)) -> Length(unit) {
Length(a.amount +. b.amount)
}
let two_meters: Length(Meters) = Length(2.0)
let two_inches: Length(Inches) = Length(2.0)
add(two_meters, two_meters)
// -> Length(4.0): Length(Meters)
add(two_meters, two_inches)
// Type error! The unit type parameters do not match.
幻影类型可以很好地配合不透明类型使用。如果其他模块无法构造Length值,那么我们就能确保不会用无效的单位类型来构造它们,并且只有上面定义的函数才能用于这些值。