Zero 言語入門 : 仕様概要

リポジトリにある実行可能なサンプルを使った、実践的な言語解説。

Zero 入門 : Zero を学ぶ

作成 : クラスキャット・セールスインフォメーション
作成日時 : 05/28/2026
バージョン : v0.1.4

* 本記事は zerolang.ai の以下のページを参考にしています :

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。

 

 

Zero 入門 : Zero を学ぶ

リポジトリにある実行可能なサンプルを使った、実践的な言語解説。

 

プログラムは main で開始

最も簡単な例は examples/hello.0 です :

pub fun main(world: World) -> Void raises {
    check world.out.write("hello from zero\n")
}

`pub` はエントリポイントをエクスポートします。`fun` は関数を宣言します。`main` は、隠しグローバル (変数) を使用する代わりに、World capability を受け取ります。

`-> Void` は、関数が有用な値を返さないことを意味します。`raises` は、関数が失敗する可能性があることを意味しています。

 
Run:

zero check examples/hello.0

出力例

ok

 

Capability を使用した副作用 (Effect)

Zero では出力は魔法ではありません。プログラムは `world.out` を通して以下のように出力します :

check world.out.write("hello from zero\n")

write は失敗する可能性があるため、`check` 付きで呼び出されます。`check` を使用する関数は `raises` を宣言する必要があります。

 

let で値をバインドする

examples/hello-let.0 はローカル・バインディングを導入しています :

pub fun main(world: World) -> Void raises {
    let message = "hello from a binding\n"
    check world.out.write(message)
}

値を変更すべきでない場合は、`let` を使用してください。値を意図的に再割り当てする場合にのみ、`let mut` を使用してください。

 

関数の記述

examples/add.0 はヘルパー関数を定義し、main からそれを呼び出します :

fun answer() -> i32 {
    return 40 + 2
}
 
pub fun main(world: World) -> Void raises {
    let value = answer()
    if value == 42 {
        check world.out.write("math works\n")
    } else {
        check world.out.write("math broke\n")
    }
}

関数シグネチャには、パラメータ名と型を列挙します。戻り値の型は明示的に指定する必要があります。関数を値とともに終了したい場合は、`return` を使用します。

 
ネイティブコンパイラは現在、明示的な整数のビット幅を認識します :

i8 i16 i32 i64
u8 u16 u32 u64
usize isize

整数リテラルは、10進数、0x 16進数、0b 2進数、0o 8進数、_ 区切り文字、および _u8 や _usize などのサフィックスをサポートします。

リテラルはコンテキストに対してチェックされます。`let byte: u8 = 255` は正しく動作します。`let byte: u8 = 256` は `zero check` で失敗します。

既存の整数値は、その正確な型を保持します。プリミティブ整数型間で意図的に変換する場合は、`as` を使用してください :

let count: u32 = 0x12c_u32
let byte: u8 = count as u8

現在サポートされているキャストは、整数型から整数型への変換に限定されています。

 
f32 と f64 は、10進浮動小数点リテラルに使用できます。型指定のない浮動小数点リテラルのデフォルトは f64 です :

let ratio: f64 = 1.0e-3
let small: f32 = 0.5
let total = ratio + 2.0

浮動小数点数は、整数型とも、異なるビット幅同士でも、暗黙には混在しません。

 
char はまた、単一引用符で囲まれたバイトリテラル用の、バイトサイズの独立したプリミティブとして使用できます。整数との間でキャストはできません :

let letter: char = 'A'
let newline: char = '\n'
let same = letter == '\x41'

f16、Unicode スカラーリテラル、および非整数値に対するキャストは、現在の公開仕様 (surface) には含まれていません。

 

制御フローの使用

Zero には通常の if / else ブロックがあります :

if value == 42 {
    check world.out.write("math works\n")
} else {
    check world.out.write("math broke\n")
}

また、現在のネイティブサブセットでは while ループもサポートしています :

while keepGoing {
    check world.out.write("loop\n")
}

整数カウンターが必要な場合は、レンジ `for` を使用してください :

for index in 0..4 {
    if index == 2 {
        continue
    }
    check world.out.write("tick\n")
}

最も近い (一番内側の) ループを抜け出すには `break` を使用し、次のイテレーションにスキップするには `continue` を使用します。

条件は Bool 型でなければならないため、truthy な整数に頼らず、値を明示的に比較してください。

直接的な条件式と明示的な状態を優先してください。チェッカーは不変バインディングへの代入を拒否するため、ループやアルゴリズムで実際に状態を変更する場合にのみ `let mut` を導入してください。

 

shape を使用したデータのモデル化

名前付きレコードには shape を使用します。examples/point.0 では point を定義し、それをヘルパー関数に渡しています :

shape Point {
    x: i32,
    y: i32,
}
 
fun sum(point: Point) -> i32 {
    return point.x + point.y
}
 
pub fun main(world: World) -> Void raises {
    let point = Point { x: 40, y: 2 }
    let total = sum(point)
    if total == 42 {
        check world.out.write("point works\n")
    }
}

shape リテラルは、そのフィールドに名前を付けます。フィールドへのアクセスには、value.field を使用します。

 

フィールドのデフォルト値の使用

shape では、呼び出し側が省略できるフィールドにデフォルト値を設定できます :

shape Counter {
    value: i32 = 0,
}
 
let counter = Counter {}

デフォルト値は、通常の具体的なイニシャライザーへ展開されます。フィールドにデフォルト値が設定されていない場合、shape リテラルは明示的に初期化する必要があります。

 

enum と choice で選択肢を表現する

名前の固定されたセットに対しては enum を使用します :

enum Status {
    ready,
    failed,
}

ペイロードを持つ可能性がある選択肢の場合は、choice を使います :

choice Result {
    ok: i32,
    err: String,
}

examples/result-choice.0 はペイロードの選択肢を構築し、それに一致させます :

let result: Result = Result.ok(42)
match result {
    .ok => value {
        if value == 42 {
            check world.out.write("choice ok\n")
        }
    }
    .err => message {
        check world.out.write("choice err\n")
    }
}

match はすべてのケースを扱う (exhaustive) 必要があります。選択肢 (choice) に ok と err がある場合は、その両方に対応します。選択肢 (choice case) のペイロードをその分岐 (arm) 内で束縛するには `=> name` を使います。

 

標準ライブラリ・モジュールのインポート

`use` を使用して標準ライブラリモジュールをインポートします。examples/codec-varint.0 は std.codec を使用します :

use std.codec
 
pub fun main(world: World) -> Void raises {
    let len = std.codec.encodedVarintLen(300)
    let checksum = std.codec.crc32("zero")
    if len == 2 && checksum > 0 {
        check world.out.write("codec primitives ok\n")
    }
}

examples/parse-cursor.0 は std.parse を使用しています :

use std.parse
 
pub fun main(world: World) -> Void raises {
    let digit = std.parse.isAsciiDigit("7")
    let ident = std.parse.isIdentifierStart("_")
    if digit && ident {
        check world.out.write("parse primitives ok\n")
    }
}

現在のネイティブコンパイラは、std.mem、std.codec、std.parse、そして経過時間を中心にした (duration-focused) std.time の初期段階のヘルパーをサポートしています。

コーデックヘルパーは、`std.codec.readU16(…) -> u16` のように、ドキュメントに記載されている (ビット) 幅を返すようになりました。

CLI 向けのヘルパーも利用可能です :

pub fun main(world: World) -> Void raises {
    let first = std.args.get(1)
    if first.has {
        let written = std.fs.write(".zero/out/name.txt", first.value)
        if written > 0 {
            check world.out.write("wrote argument\n")
        }
    }
}

std.args.get は、要求された引数が存在しない可能性があるため、Maybe<String> を返します。

現在の std.fs ヘルパーは hosted (ホスト環境依存) API です。Fs、File、owned<File> の具体的なリソース例が必要な場合は、標準ライブラリのリファレンスを参照してください。

 

パッケージの構成

パッケージは、zero.json マニフェストと、src/ ディレクトリ下のソースファイルで構成されます :

{
  "package": { "name": "systems-package", "version": "0.1.0" },
  "targets": { "cli": { "kind": "exe", "main": "src/main.0" } }
}

examples/systems-package/src/main.0 はモジュールとローカル宣言をインポートします :

use std.codec
use std.parse
use std.time
 
pub fun main(world: World) -> Void raises {
    defer cleanup()
    let current: Status = status()
    let result: Result = Result.ok
    let word = std.codec.readU32("abcd")
    let digits = std.parse.scanDigits("123abc")
    let duration = std.time.add(std.time.ms(5), std.time.seconds(1))
    if digits == 3 && word > 0 && std.time.asMsFloor(duration) > 0 {
        check world.out.write("systems package\n")
    }
}

Check the package:

zero check examples/systems-package

 

テストの実行

Zero のテストブロックはソースコードのすぐ隣に置かれます :

test "addition is stable" {
    expect(40 + 2 == 42)
}

Run tests with:

zero test conformance/native/pass/test-blocks.0
zero test --json --filter addition conformance/native/pass/test-blocks.0

失敗したテストには、失敗したテスト名と非ゼロの終了コードが含まれます。

 

クロスターゲットのチェック

ターゲット名は明示的です。サポート状況を確認するには `zero targets` を使用し、それから、check, build, graph, や size に –target オプションを渡します :

zero targets
zero check --target linux-musl-x64 examples/memory-package
zero build --target linux-musl-x64 examples/memory-package --out .zero/out/memory-package

チェッカーは、ターゲットに依存しない (target-neutral) ビルドにおけるホスト型 std.fs のような、利用できない機能を拒否します。

 

診断機能 (Diagnostics) の使用

診断機能は人間とエージェントの両方に対して十分に安定しています :

zero check --json conformance/check/fail/unknown-name.0
zero explain NAM003
zero fix --plan --json conformance/check/fail/unknown-name.0

各 JSON 診断には、コード、範囲 (span)、期待値/実際値フィールド、ヘルプ、安全性修正、メタデータ修復が含まれます。

 

defer を使用したクリーンアップの理解

`defer cleanup()` は、現在のスコープの終了時にクリーンアップをスケジュールします :

pub fun main(world: World) -> Void raises {
    defer cleanup()
    check world.out.write("work\n")
}

スコープが終了する際に実行される必要があるクリーンアップ処理には defer を使用します。これは、return、break、continue による終了も含まれます。

 

以上