Phantomtypen sind Typparameter eines benutzerdefinierten Typs, die in keinem der Wertkonstruktoren dieses Typs verwendet werden.
Das ist etwas abstrakt, deshalb folgt hier ein Beispiel:
pub type Length(unit) {
Length(amount: Float)
}
In diesem Beispiel wird der Typparameter unit nicht im Wertkonstruktor Length verwendet, also ist unit ein Phantomtyp.
Dieser ungenutzte Typparameter mag nutzlos erscheinen, aber er kann verwendet werden, um weitere Einschränkungen dafür hinzuzufügen, wie Length-Werte verwendet werden können.
Zum Beispiel könnten wir eine Funktion double haben, die die Länge multipliziert. Sie funktioniert mit Längen jeder Einheit, also ist der Typparameter eine generische Typvariable.
// This function accepts all Length values
pub fn double(length: Length(unit)) -> Length(unit) {
Length(length.amount *. 2.0)
}
Wir könnten auch eine Funktion add_inch haben, die nur funktioniert, wenn die Länge in Zoll ist.
// 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)
}
Die Funktion add_inch akzeptiert keine Längen mit einem anderen Einheitenparameter; der Phantomtyp wurde verwendet, um sicherzustellen, dass nur die richtige Einheit verwendet wird.
Eine Funktion kann auch so geschrieben werden, dass sie sicherstellt, dass zwei Längenwerte dieselbe Einheit haben, indem für beide dieselbe Typvariable verwendet wird.
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.
Phantomtypen lassen sich gut mit opaken Typen kombinieren. Wenn andere Module keine Length-Werte konstruieren können, können wir sicherstellen, dass sie nicht mit einem ungültigen Einheitentyp konstruiert werden und dass nur die oben definierten Funktionen mit ihnen verwendet werden können.
Lucy hat einen Online-Shop für Sticker, in dem sie niedliche Sticker verkauft, auf denen die Lieblingsprogrammiersprachen aller Leute zu sehen sind. Menschen aus aller Welt kaufen ihre Sticker, und sie hat Schwierigkeiten, mit all den verschiedenen Währungen umzugehen.
Erstelle ein Programm, mit dem Lucy Preise berechnen kann und dabei sicher sein kann, dass sie immer die richtige Währung verwendet.
Usd, Eur und Jpy
Diese Typen werden verwendet, um die verschiedenen Währungen darzustellen, die Lucys Kundinnen und Kunden zum Kauf ihrer Sticker verwenden.
Sie sollen als Phantomtypen verwendet werden und brauchen keine Konstruktoren zu haben.
Money.Der Typ Money sollte ein Int-Feld für den Geldbetrag und einen Phantomtyp-Parameter für die Währung haben; außerdem sollte er ein opaker Typ sein.
dollar, euro und yen
Definiere die Funktionen dollar, euro und yen, die ein Int-Argument entgegennehmen und einen Money-Wert mit der richtigen Währung zurückgeben.
total
Definiere die Funktion total, die eine Liste von Money-Werten entgegennimmt und den Gesamtbetrag des Geldes in der Liste zurückgibt.
total([euro(120), euro(200), euro(145)])
// -> euro(465)
Melde dich bei Exercism an, um Gleam mit 33 Konzepte122 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.