ビルトイン型
Zero は、小さく規則的なプリミティブ型のセットを提供します。エキゾチックなものも意外なものもなく、すべてのシステム言語が必要とするものを、一貫した名前で揃えているだけです。
| ファミリー | 型 | 備考 |
|---|---|---|
| 符号付き整数 | i8、i16、i32、i64 | 2 の補数表現。 |
| 符号なし整数 | u8、u16、u32、u64 | 0 と正のみ。 |
| ポインタサイズ | usize、isize | プラットフォームのポインタ幅に一致。 |
| 浮動小数点 | f32、f64 | IEEE-754。 |
| ブーリアン | bool | true または false。 |
| 文字 | char | 単一の Unicode スカラー。 |
| 文字列 | String | UTF-8 文字列。 |
| 空 | Void | 「有用な値はない」。 |
これが日常的に触れるプリミティブの全リストです。複合型——shape、enum、choice——はこれらから作られます。
整数
整数型は統一的な命名パターンに従います。符号付きは i、符号なしは u、続いてビット幅です。つまり i32 は 32 ビット符号付き整数、u8 は符号なしバイト、i64 は 64 ビット符号付き整数。
let small_signed: i8 = -120
let byte: u8 = 250
let id: i32 = 1
let big: i64 = 9_000_000_000
let index: usize = 0
サフィックスのないリテラルのデフォルトは、周囲のコンテキストが別のものを強制しない限り i32 です。
let answer = 42 // i32
特定の幅が必要な場合は、リテラルにサフィックスを付けるか、バインディングに注釈します。
let byte = 250_u8 // 型付きリテラル
let byte: u8 = 250 // 型付きバインディング
どちらの形も同じ値を生成します。リテラルサフィックス形式は、リテラルを直接関数に渡すときや構造体を組み立てるときに便利です。
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
どの幅を選ぶか
簡単な目安です。
- ほとんどの符号付き演算には
i32。 数えるものほぼ何にでも十分広く、どのプラットフォームでも高速。 - バイトレベルの作業には
u8。 ファイルのバイト、バッファのバイト、ネットワーク越しのバイト。 - 範囲が重要な非負カウントには
u32/u64。 2GB を超えるファイルオフセット、大きなカウント。 - サイズとインデックスには
usize。 ポインタサイズ——プラットフォームがメモリアドレッシングに使うものに一致。 - エポックからの時間などには
i64。 数百年分のナノ秒に十分な大きさ。
収まる最も小さな型を選ぶのは良い習慣ですが、小さすぎる型を選んでオーバーフローする方が、1 ビット広めの型を選ぶよりずっと大きな問題です。
ブーリアン
let ok = true
let done: bool = false
bool はちょうど 2 つの値、true と false を持ちます。これらはどこかからインポートする定数ではなく、リテラルです。if や while の条件は bool です——整数や文字列に対する暗黙の真偽値解釈はありません。
if ok {
check world.out.write("yes\n")
} else {
check world.out.write("no\n")
}
条件分岐の詳細は If/Else で扱います。
浮動小数点
f32 と f64 はそれぞれ 32 ビット・64 ビットの IEEE-754 浮動小数点数です。小数の値が必要なとき——測定、比率、幾何——に使います。通貨に対する厳密な算術には、浮動小数点よりも最小単位(セント、satoshi)の整数を使うのが望ましいです。
let ratio: f32 = 0.5
let pi: f64 = 3.141592653589793
サフィックスのない浮動小数点リテラルのデフォルトは f64 です。
文字と文字列
char は単一の Unicode スカラー値を保持します。
let initial: char = 'Z'
String は文字のシーケンスで、標準ライブラリでは通常 UTF-8 でエンコードされます。文字列リテラルはダブルクォートを使います。
let message: String = "hello from zero\n"
期待されるエスケープシーケンスは動きます——改行は \n、タブは \t、リテラルなバックスラッシュは \\、リテラルなダブルクォートは \"。
let multi_line = "line one\nline two\n"
標準ライブラリは、低水準作業のための文字列に対するバイトレベルのビューを公開します。std.mem.span("zero") の形はバイトに対する Span<u8> を返します——パース、ハッシュ、バイト単位の比較で便利です。
Void
Void は Zero の「有用な戻り値はない」型です。副作用のために存在する関数が使います。
pub fun main(world: World) -> Void raises {
check world.out.write("hello\n")
}
main は何かを書いて返ります。返す値がないので、型は Void です。World に触れるほとんどの関数で Void を見かけます——結果ではなくエフェクトのために選ばれているからです。
数値リテラルのアンダースコア
長い数値リテラルは視覚的な区切りとしてアンダースコアを使えます。コンパイラーは無視するので、純粋に読みやすさのための機能です。
let big = 9_000_000_000_i64
let bytes = 1_048_576_u32 // 1 MiB
桁が数えにくくなったらどこにでも入れて構いません。
型付きリテラルサフィックス早見表
| サフィックス | 型 | 例 |
|---|---|---|
_i8 / _i16 / _i32 / _i64 | 符号付き整数 | 127_i8 |
_u8 / _u16 / _u32 / _u64 | 符号なし整数 | 255_u8 |
_usize / _isize | ポインタサイズ | 0_usize |
_f32 / _f64 | 浮動小数点 | 0.5_f32 |
周囲のコンテキストが型を確定させない場面で値を構築するときに役立ちます。
次回: 関数
プリミティブは、それを使って何かするものがなければ役に立ちません。次のドキュメントでは Zero の 関数 を扱います——宣言の仕方、値の返し方、そしてそれらを組み合わせて本物のプログラムを構築する方法です。
よくある質問
Zero にはどんなプリミティブ型がありますか?
Zero には、サイズ付き符号付き整数 i8・i16・i32・i64、符号なし整数 u8・u16・u32・u64、ポインタサイズ整数 usize と isize、浮動小数点 f32 と f64、bool、char、String、そして有用な値を返さない関数のための Void が標準で備わっています。
Zero のデフォルトの整数型は?
42 のようなサフィックスのない整数リテラルは、コンテキストが別の型を強制しない限りデフォルトで i32 になります。特定の幅を使うには 42_u8 や 42_i64 のようにサフィックス付きリテラルを書くか、let count: u8 = 42 のようにバインディングの型を明示的に注釈します。
Zero には専用の文字列型がありますか?
はい。"hello" のような文字列リテラルにはビルトインの文字列型があり、標準ライブラリは通常それをバイトのシーケンス(多くは UTF-8)として扱います。低水準のバイト操作には、標準ライブラリがスパンとバイトレベルのユーティリティを公開します。文字レベルの操作には、個々のスカラー値のための char があります。
Zero における Void の意味は?
Void は、有用な値を生成しない関数の戻り値型です——副作用のためだけに存在する関数のもの。慣用的な pub fun main(world: World) -> Void raises のシグネチャは、main が値を生成するためではなく I/O を行って終了するために存在するので、Void を使います。
Zero の i32 と u32 の違いは?
i32 は符号付き 32 ビット整数で、範囲は −2,147,483,648 から 2,147,483,647 です。u32 は符号なしで範囲は 0 から 4,294,967,295。負の値が意味を持つ場合は符号付きを、負の値がバグになる場合(カウント、インデックス、サイズなど)は符号なしを使いましょう。