Kagari
キーワードを入力してドキュメントを検索します。

特殊な型、トレイト、属性

言語トレイト

Kagari のトレイトはゲームのための道具ではありません。標準ライブラリが固定のトレイト群を宣言し、どれも #[builtin] が付いています。それらを実装するのも標準ライブラリだけです。トレイトがあるのは、オーバーロードや暗黙の変換なしに std のシグネチャを型検査するため、そしてコンパイラが規則を述べられるようにするため(「== には Eq が必要」「rng_choose は RandChoose を引く」)です。

ゲームがこれらのトレイトを使う方法は一つだけです。自分のジェネリックパラメータへの境界です。そのうち Eq と RandChoose の二つは、ゲームが宣言した適切な型に対して自動的にも成り立ち、ShaderArg はゲームが #[shader_arg] を付けた構造体に成り立ちます。

概要

トレイト宣言場所プレリュード実装する型使う場所
Eqstdありプリミティブ、関数ポインタ、構成要素がすべて Eq の型(構造的に)、一部のビルトイン型==、!=、ui::select
IntegerstdありInt<lo, hi> と Rust の整数into、saturate
ToTextstd::narrative::textなしText、String、整数、Rat、Decimalt![…] の {expr}、to_text
RandChoosestdありInt<lo, hi> とフィールドのないすべての列挙型rng_choose
Assetstdなし5 つのファイルのアセット型と 6 つのシェーダー型asset
Stepstd::narrativeなしSay、Choice<A, N>push_step、s!、choice!
ShaderArgstd::screen::shaderなし() と #[shader_arg] 構造体filter などのシェーダーのコンストラクター
Shaderstd::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 ブロックは、型と定数についてジェネリックにできます。型パラメータには + でつないだ境界を付けられます。

kis
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

kis
#[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 TT が 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

kis
#[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()変換先の型の範囲に切り詰めた値
kis
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

kis
#[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

kis
#[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)。

kix
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

kis
#[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

kis
#[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

kis
#[builtin] pub trait ShaderArg {}

ShaderArg は、シェーダーが引数として受け取れる型を表します。ユニット型 () と、#[shader_arg] を付けたすべての構造体です。std::screen::shader のコンストラクターは、filter<A: ShaderArg>(shader: ColorShader<A>, args: A) のように引数型をこれで制約します。std::screen::shader を参照してください。

Shader

kis
#[builtin] pub trait Shader {}

Shader は 6 つのシェーダー型を表します。標準ライブラリが任意のロールのシェーダーを受け取るために使うもので、ゲームが使うことはありません。

クロージャ型はトレイトではない

Fn(A) -> B、const Fn(A) -> B、pushdown Fn(A) -> B は Rust の Fn トレイトに似ていますが、Kagari では型です。種別を持つクロージャ型で、境界には使えません。関数ポインタ型とクロージャ型を参照してください。

最終更新日 2026年10月29日