幽靈型別是自訂型別裡的型別參數,但它沒有用在該型別的任何值建構子上。
這樣講有點抽象,來看個例子吧:
pub type Length(unit) {
Length(amount: Float)
}
在這個例子中,unit型別參數並沒有用在 Length值建構子裡,所以 unit 就是幽靈型別。
這個沒派上用場的型別參數看起來沒什麼用,不過我們可以拿它來對 Length值的使用方式加上更多限制。
舉例來說,我們可以寫一個函式 double,把長度乘以 2。它適用於任何單位的長度,所以這個型別參數是一般的型別變數。
// 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值,我們就能確保這些值不會帶著無效的單位型別被建構出來,而且只有上面定義的函式能搭配它們使用。