特殊な型、トレイト、属性
言語トレイト
Kagari のトレイトはゲームのための道具ではありません。標準ライブラリが固定のトレイト群を宣言し、どれも #[builtin] が付いています。それらを実装するのも標準ライブラリだけです。トレイトがあるのは、オーバーロードや暗黙の変換なしに std のシグネチャを型検査するため、そしてコンパイラが規則を述べられるようにするため(「== には Eq が必要」「rng_choose は RandChoose を引く」)です。
ゲームがこれらのトレイトを使う方法は一つだけです。自分のジェネリックパラメータへの境界です。そのうち Eq と RandChoose の二つは、ゲームが宣言した適切な型に対して自動的にも成り立ち、ShaderArg はゲームが #[shader_arg] を付けた構造体に成り立ちます。
概要
| トレイト | 宣言場所 | プレリュード | 実装する型 | 使う場所 |
|---|---|---|---|---|
Eq | std | あり | プリミティブ、関数ポインタ、構成要素がすべて Eq の型(構造的に)、一部のビルトイン型 | ==、!=、ui::select |
Integer | std | あり | Int<lo, hi> と Rust の整数 | into、saturate |
ToText | std::narrative::text | なし | Text、String、整数、Rat、Decimal | t![…] の {expr}、to_text |
RandChoose | std | あり | Int<lo, hi> とフィールドのないすべての列挙型 | rng_choose |
Asset | std | なし | 5 つのファイルのアセット型と 6 つのシェーダー型 | asset |
Step | std::narrative | なし | Say、Choice<A, N> | push_step、s!、choice! |
ShaderArg | std::screen::shader | なし | () と #[shader_arg] 構造体 | filter などのシェーダーのコンストラクター |
Shader | std::screen::shader | なし | 6 つのシェーダー型 | std の内部 |
プレリュードにないトレイトは、std::narrative::text::ToText のようにパスで書くか、use でインポートします。
ゲームに対する規則
- ゲームの中の
traitアイテムはエラーです(E1012)。 - ゲームの中の
impl Trait for Typeはエラーです(E1023)。Eqの場合、メッセージはEqが自動であることを指摘します。 derive、ユーザー定義の関連型、<T as Trait>::fのような修飾パスはありません。- ゲームは自分の構造体と列挙型に固有の
implブロックを書き、メソッドや関連関数を定義できます。これはトレイトとは無関係です。
std の中では、すべてのトレイトが #[builtin] でなければなりません(E1013)。
境界
関数、構造体、列挙型、impl ブロックは、型と定数についてジェネリックにできます。型パラメータには + でつないだ境界を付けられます。
use std::narrative::text::{ToText, to_text};
const fn same<T: Eq>(a: T, b: T) -> bool { a == b}
const fn describe<T: Eq + ToText>(a: T, b: T) -> Text { if a == b { to_text(a) } else { "different" }}- 境界はパラメータリストにだけ書きます。
where節はありません。 - 境界はトレイトを指さなければなりません(
E2008)。境界を実装しない型引数はE2026です。 - ジェネリックなコードの中では、型パラメータはちょうど境界のトレイトだけを実装します。
T: EqのないTに対するa == bはE2017です。 pushdown fnの中では、すべての型引数が有限型でなければなりません。ジェネリックなコードは引数の組ごとに具体化されるので、物語は有限なプログラムのままです。
Eq
#[builtin] pub trait Eq {}Eq は、値を == と != で比較できる型を表します。両辺は同じ型で、その型は Eq でなければなりません(E2017)。std::ui の関数 select も値の型に T: Eq を要求します。
Eq は自動的に実装されます。書くことは何もありません。
| 型 | Eq |
|---|---|
bool、()、Int<lo, hi>、Rust の整数 | 常に |
| 関数ポインタと名前付き関数 | 常に。同一性で比較します |
| タプル、配列 | すべての要素型が Eq のとき |
Kagari で宣言された構造体と列挙型(皆さんのものも std のものも) | すべてのバリアントのすべてのフィールドが Eq のとき。同じように組み立てられた二つの値が等しくなります |
&T、&mut T | T が Eq のとき。指す先の値を比較します |
#[builtin] 型 | std の impl Eq によってのみ:String、Eq な T の Vec<T>、Rat、Decimal、Text、Screen、6 つのアセット型、6 つのシェーダー型、ShaderArgs |
| クロージャ | 決してならない |
したがって Setting<T>、Meta<T>、Narrative、Element、Placed、Arm、Divergence、画面の部品(Entity、Prop<T>、各レイヤー、Hud、ChoiceMenu、Camera、Channel)、保留中の変更(Change<T>、Swap、ChannelChange)は Eq ではなく、それらを含む構造体や列挙型も Eq ではありません。Kagari に浮動小数点数がない理由の一つは、すべての数値型を Eq にするためです。
Integer
#[builtin] pub trait Integer { const fn into<T: Integer>(self) -> T; const fn saturate<T: Integer>(self) -> T;}Integer を実装するのは Int<lo, hi> と、u8、u16、u32、u64、u128、i8、i16、i32、i64、i128、usize、isize です。この二つのメソッドが整数型どうしの唯一の変換で、変換先の型は文脈から推論されます。
| メソッド | 結果 |
|---|---|
x.into() | 同じ値。変換元の型のすべての値が変換先の型に収まらなければコンパイルエラー(E2018) |
x.saturate() | 変換先の型の範囲に切り詰めた値 |
static MUSIC: Setting<Volume> = setting(volume(60));
fn set_music_level(level: u32) { let level: Int<0, 100> = level.saturate(); MUSIC.set(volume(level));}
const fn label_width(chars: Int<0, 40>) -> u32 { let n: u32 = chars.into(); n * 16}as キャストはありません(E2019)。数値を参照してください。
ToText
#[builtin] pub trait ToText {}#[builtin] pub const fn to_text<T: ToText>(value: T) -> Text;ToText は、t![…] の {expr} 項目で埋め込める型を表します。{expr} は to_text(expr) の呼び出しです。実装するのは Text、String、Int<lo, hi>、すべての Rust の整数、Rat、Decimal です。bool と列挙型は ToText ではないので、match で分岐してテキストを書きます。それ以外の型を埋め込むと E2026 です。
pushdown fn の中では、Int<0, 5> の物語変数のような有限な実行時の値に対する to_text は他の const fn 呼び出しと同じく表化されるので、台詞は物語の状態の有限な関数のままです。
RandChoose
#[builtin] pub trait RandChoose {}#[builtin] pub pushdown fn rng_choose<T: RandChoose>() -> T;RandChoose は、シーンが rng_choose::<T>() で無作為に引ける型を表します。実装するのは Int<lo, hi> と、バリアントが一つ以上あってどのバリアントもフィールドを持たないすべての列挙型(自動)です。bool とデータを持つ列挙型は RandChoose ではありません。rng_choose を呼べるのはシーンだけです(E3024)。
enum Weather { Sunny, Rainy, Snowy }
#[scene]pushdown fn Morning() { match rng_choose::<Weather>() { Weather::Sunny => s!(t!["The sun is out."]), Weather::Rainy => s!(t!["It is raining."]), Weather::Snowy => s!(t!["Snow covers the yard."]), }}乱数を参照してください。
Asset
#[builtin] pub trait Asset {}#[builtin] pub const fn asset<A: Asset>(path: narrative::Text) -> A;Asset は、値がちょうどプログラムのアセット定数である型を表します。ImageAsset、AudioAsset、VoiceAsset、VideoAsset、FontAsset と、6 つのシェーダー型 ColorShader<A>、MixShader<A>、TextureShader<A>、MaskShader<A>、LocalMotionShader<A>、TransitionalMotionShader<A> です。これはアセット定数を宣言する asset の境界です。アセット型を参照してください。
Step
#[builtin] pub trait Step { type Output;}#[builtin] pub pushdown fn push_step<S: Step>(s: S) -> S::Output;Step は、物語が中断できる値を表します。実装するのは、s!(…) と書くステップ Say(Output = ())と、choice!{…} と書くステップ Choice<A, N>(Output = A、アームの値の型)です。push_step はステップを実行し、その出力で再開します。関連型を持つ唯一のトレイトです。ステップを実行できるのはシーンだけです(E3002)。ステップを参照してください。
ShaderArg
#[builtin] pub trait ShaderArg {}ShaderArg は、シェーダーが引数として受け取れる型を表します。ユニット型 () と、#[shader_arg] を付けたすべての構造体です。std::screen::shader のコンストラクターは、filter<A: ShaderArg>(shader: ColorShader<A>, args: A) のように引数型をこれで制約します。std::screen::shader を参照してください。
Shader
#[builtin] pub trait Shader {}Shader は 6 つのシェーダー型を表します。標準ライブラリが任意のロールのシェーダーを受け取るために使うもので、ゲームが使うことはありません。
クロージャ型はトレイトではない
Fn(A) -> B、const Fn(A) -> B、pushdown Fn(A) -> B は Rust の Fn トレイトに似ていますが、Kagari では型です。種別を持つクロージャ型で、境界には使えません。関数ポインタ型とクロージャ型を参照してください。