الأنواع الشبحية هي معاملات أنواع لنوع مخصص لا تُستخدم في أي من بواني القيم الخاصة بذلك النوع.
هذا كلام مجرّد بعض الشيء، لذا إليك مثالًا:
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، أمكننا ضمان عدم إنشائها بنوع وحدة غير صالح، وأن الدوال المعرَّفة أعلاه وحدها هي التي يمكن استخدامها معها.