Kagari は静的に型付けされます。すべての値はコンパイル時にわかる 1 つの型を持ちます。型はアイテムのシグネチャでは明記し、関数本体の中では推論されます。
型の式
| 構文 | 型 |
|---|---|
Path、Path<Args> | 名前の付いた型。プリミティブ、構造体、列挙型、型エイリアス、ジェネリクスパラメータ |
() | ユニット型。空のタプル |
(A,)、(A, B)、… | タプル |
(A) | A。括弧はグループ化だけです |
[T; N] | 要素数 N の配列 |
&T、&mut T | 共有参照または可変参照 |
fn(A) -> R、const fn(A) -> R、pushdown fn(A) -> R、scene fn(A) -> R | 関数ポインタ |
Fn(A) -> R、const Fn(A) -> R、pushdown Fn(A) -> R | クロージャ型 |
_ | プレースホルダ。「この型を推論する」 |
Self | impl の中での対象の型 |
-> R のない関数ポインタ型やクロージャ型は () を返します。プレースホルダ _ は本体の中の let の注釈やジェネリクス引数では使えますが、アイテムのシグネチャでは使えません(E2011)。スライス型 [T]、str、! 型の構文、dyn や impl Trait の型、生ポインタはありません。
概要
| 型 | 値 | 備考 |
|---|---|---|
bool | true、false | |
() | () | 結果を持たないブロックや関数の値 |
Int<lo, hi> | lo から hi までの整数 | プリミティブ。数値を参照 |
u8 … u128、i8 … i128、usize、isize | Rust と同じ | Rust の整数を参照 |
Decimal、Rat | 正確な十進数と分数 | 数値を参照 |
Text | 定数テキスト | Text と String を参照 |
String | 実行時のテキスト | |
| タプル、配列 | (bool, Route)、[Int<0, 3>; 4] | |
Vec<T> | 伸縮するリスト | |
Range<T> | 0..4、3..=5 | 範囲を参照 |
| 構造体、列挙型 | ユーザーが宣言するもの。プレリュードの Option<T> と Result<T, E> | |
| 参照 | &T、&mut T | 値、参照、クロージャを参照 |
| 関数ポインタ、クロージャ | fn(u32) -> bool、Fn(u32) -> bool | クロージャ型とポインタ型を参照 |
| ビルトイン型 | Screen、Narrative、Element、Setting<T>、Meta<T>、アセット型など | 不透明なハンドル。ビルトイン型を参照 |
浮動小数点型はありません。物語が実行時に保持できる型は有限型に限られます。
プリミティブ型
bool、Int、12 個の Rust の整数型はプリミティブ型です。宣言を持たず、他のすべての名前の後に探されます(パスを参照)。Int は常にちょうど 2 つの境界を取り、他のプリミティブはジェネリクス引数を取りません(E2005)。ユーザーのコードはプリミティブ型に impl を追加できません。
Text と String
| 型 | 内容 |
|---|---|
Text | プログラムの定数テキスト。素の文字列リテラル("Mio")か、ルビやテキスト効果を含む t![…] のリッチテキストです。文字列リテラルの型はすべて Text です。Text は有限型です。その値はプログラムに書かれたテキストなので、物語が保持できます |
String | fn のコードが実行時に組み立てる文字列。有限型ではありません |
どちらも Eq です。Text は std::narrative::text で、String は std で宣言されています。どちらもプレリュードにあります。
タプル、配列、Vec
- タプル
(A, B, …)は型の異なる値をまとめます。フィールドは.0、.1、… です。要素 1 つのタプルは(A,)と書き、()はユニット型です。 - 配列
[T; N]は型Tの値をちょうどN個持ちます。Nは型レベル定数です。配列は[a, b, c]か[value; N]と書き、a[i]でインデックスします。範囲外のインデックスは、コンパイル時ならエラー、実行時なら VM パニックです。 Vec<T>は実行時に長さが変わるリストです。Vec::new()、push、len、is_empty、get、setがあります。有限型ではありません。STD リファレンスを参照してください。
構造体と列挙型
構造体と列挙型は名前で区別されます。同じフィールドを持つ 2 つの宣言は別の型です。ジェネリックにできます。標準ライブラリは Option<T>(None、Some(T))と Result<T, E>(Ok(T)、Err(E))を宣言しており、そのバリアントはプレリュードにあります。宣言の形はアイテムにあります。
範囲
a..b と a..=b は標準の構造体 Range<T> の値です。
pub struct Range<T> { pub start: T, pub end: T, pub inclusive: bool,}a..b は b を含まず、a..=b は含みます。値としての範囲は a..b と a..=b だけで、a.. や ..b などそれ以外の形は E2030 です。パターンには独自の範囲の形 a..、..=b、a..b、a..=b があります(範囲パターンを参照)。..b というパターンはなく、パターンの中の単独の .. は残余パターンです。範囲は for で反復します(制御フローとループを参照)。
ジェネリクス
関数、構造体、列挙型、型エイリアス、impl ブロックはジェネリクスパラメータを持てます。
struct Pair<T> { a: T, b: T }
fn first<T, const N: usize>(items: [T; N]) -> T { items[0]}- 型パラメータ
Tには境界を付けられます。T: Eq、T: Eq + Integerのように書きます。 - 定数パラメータ
const N: usizeは整数型の定数を表します。Int<lo, hi>自体は、i64の定数パラメータを 2 つ持つプリミティブです。 - ジェネリクス引数は推論されるか、明示します。型の中では
Pair<u8>、式の中ではターボフィッシュでfirst::<u8, 3>(…)と書きます。引数の数の誤りはE2005です。 - ジェネリックなコードは単相化されます。コンパイラは、プログラムが使う引数の組み合わせごとに複製を作ります。
pushdown fnの中では型引数はすべて有限型でなければならず、物語は有限のプログラムのままです。 - ライフタイム、
where節、既定の引数、独自の関連型はありません。
型レベル定数
配列の長さ、Int の境界、定数ジェネリクス引数は型レベル定数です。ジェネリクス引数としては、整数リテラル(Square<8>)、負のリテラル(Int<-5, 5>)、定数パラメータや const アイテムの名前(Int<0, MAX>)、波括弧で囲んだ式(Int<0, { MAX * 2 }>)のいずれかで書きます。式に使えるのは、整数リテラル、単項 -、+ - * / %、最後の式だけからなるブロック、定数パラメータ、値がこうした式である const アイテムだけです(E2002)。定数が期待される所に型を書くと E2007 です。
const MAX: i64 = 5;static mut TRUST: Int<0, MAX> = 0;static mut DOUBLE: Int<0, { MAX * 2 }> = 0;トレイト境界
境界には標準ライブラリのトレイトを指定します。コードはトレイトを宣言・実装できませんが、要求することはできます。
| トレイト | 実装する型 | 使えるもの |
|---|---|---|
Eq | 構造的な等価性を持つすべての型。等価性を参照 | ==、!= |
Integer | Int<lo, hi> と Rust の整数 | into、saturate。変換を参照 |
RandChoose | フィールドなし列挙型と Int<lo, hi> | rng_choose::<T>() |
Asset | アセット型 | asset::<A>(…) |
Step | ステップ Say と Choice | push_step。関連型 Output |
ToText | Text、String、Int<lo, hi>、Rust の整数、Rat、Decimal | t![…] の埋め込み {expr} |
境界を満たさないジェネリクス引数は E2026 です。境界があると、そのトレイトのアイテムをパラメータに対して使えます。S: Step なら S::Output、T: Integer なら value.into() です。詳しくは言語トレイトを参照してください。
等価性
derive はありません。== と != は両辺に Eq を必要とし(E2017)、Eq は自動で実装されます。
bool、Int<lo, hi>、Rust の整数。- フィールドや要素がすべて
Eqである構造体、列挙型、タプル、配列。構造的に比較し、同じように組み立てられた 2 つの値が等しくなります。 - 関数ポインタと名前付き関数。同一性で比較します。
TがEqのときの&Tと&mut T。指す先の値を比較します。- 標準ライブラリが
Eqと宣言しているビルトイン型。String、Vec<T>(TがEqのとき)、Rat、Decimal、Text、Screen、アセット型です。
クロージャは決して Eq ではありません。それ以外のビルトイン型も Eq ではありません。
有限型
物語が実行時に保持するのは有限型だけです。有限型とは、値が有限個で、コンパイラが列挙できる型です。要点は次のとおりです。
| 有限 | 有限でない |
|---|---|
bool、()、Int<lo, hi> | Rust の整数、Rat、Decimal |
| 有限型からなる構造体、列挙型、タプル、配列 | String、Vec<T>、再帰的な型 |
Text とアセット型 | Screen などのビルトインのハンドル |
pushdown fn、scene fn、const fn のポインタ | fn のポインタ、クロージャ |
有限な T の &T と &mut T(パラメータとしてのみ) |
任意の型の定数式は、値がコンパイル時に計算されるので、物語の中にも書けます。完全な規則は関数種別にあります。
関数ポインタ型とクロージャ型
関数ポインタ型とクロージャ型は呼び出すコードの種別を持つので、呼び出し規則はそれらを通しても成り立ちます。
| 型 | 保持するもの |
|---|---|
fn(A) -> R、const fn(A) -> R | その種別の名前付き関数 |
pushdown fn(A) -> R | 名前付きの即時手続き |
scene fn(A) -> R | 名前付きのシーン(構文は暫定) |
Fn(A) -> R、const Fn(A) -> R、pushdown Fn(A) -> R | その種別のクロージャまたは関数(構文は暫定) |
型の変換を含めて値、参照、クロージャで説明します。
型強制
ある型の値が期待される所に別の型の値を与えると、次の暗黙の変換が適用されます。
| 変換元 | 変換先 |
|---|---|
| 整数リテラル | その値を範囲に含む任意の整数型 |
Int<l1, h1> | l2 <= l1 かつ h1 <= h2 である Int<l2, h2>(拡大) |
&mut T | &T |
| 名前付き関数またはタプルのコンストラクタ | 同じ種別とシグネチャの関数ポインタ |
| 名前付き関数、関数ポインタ、クロージャ | 同じ種別のクロージャ型(シーンを除く) |
| 何もキャプチャしないクロージャ | 同じ種別の関数ポインタ |
return、break、continue、終わらない loop の型 | 任意の型 |
それ以外の型の変更は x.into() のように明示します。
型推論
本体の中では、Rust と同じく型は使われ方から推論されます。アイテムのシグネチャは決して推論されません。パラメータの型、戻り値型、定数と static の型は常に書きます。推論で型が決まらない場合は注釈が必要です(E2029)。
fn demo() { let names: Vec<Text> = Vec::new(); let level: Int<0, 5> = 3;}