Gleamの不透明型とは、その型を定義したモジュールだけが値を作ったりパターンマッチしたりできるカスタム型のことです。決まった使い方だけを許したい型を作るときに便利です。
不透明型は、opaqueキーワードを使って定義します。
pub opaque type PositiveInt {
PositiveInt(inner: Int)
}
このPositiveInt型は、整数を使いたいけれど0以上でなければならない場面で使います。通常のGleamのIntは負の値も取れるため、そのままでは使えません。
この型を定義したモジュールでは、内側の整数値を取り出す関数と、PositiveInt型を作る関数を定義できます。後者は、値が正でなければエラーを返します。
pub fn from_int(i: Int) -> Result(PositiveInt, String) {
case i {
_ if i < 0 -> Error("Value must be positive")
_ -> Ok(PositiveInt(i))
}
}
pub fn to_int(i: PositiveInt) -> Int {
i.inner
}
このAPIがあれば、ほかのモジュールが負の値でPositiveIntを作ることはできません。そのため、PositiveIntを受け取る関数は、その値が正であることを確信できます。
勘の鋭い方なら、前の演習のTreasureChest型がそれほど安全ではなかったことにお気づきでしょう。
get_treasure関数を使うときはパスワードを渡す必要がありましたが、パスワードを知らなくてもTreasureChest型を分解すれば宝を取り出せてしまいました。
そこで、不透明型を使ってこれを解決しましょう。
TreasureChest不透明型を定義するTreasureChestには2つのフィールドがあります。
String型のパスワード。TreasureChest型は不透明でなければなりません。
create関数を定義するこの関数は2つの引数を取ります。
String型のパスワード。この関数は、パスワードと値を持つTreasureChestを返します。
パスワードが8文字より短い場合、この関数はPassword must be at least 8 characters longというエラーを返します。
open関数を定義するこの関数は2つの引数を取ります。
TreasureChest。String型のパスワード。パスワードがTreasureChest内のパスワードと一致する場合、この関数は宝を返します。一致しない場合は、Incorrect passwordというエラーを返します。