«نوع فانتوم» به پارامترهای نوعی از یک نوع سفارشی گفته میشود که در هیچیک از سازندههای مقدار آن نوع استفاده نمیشوند.
این تعریف کمی انتزاعی است، پس یک مثال میآوریم:
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 را بسازند، میتوانیم تضمین کنیم که آنها با نوع واحد نامعتبری ساخته نمیشوند و فقط توابع تعریفشده در بالا با آنها کار میکنند.