inline fn / 関数ポインタ
『Zig』では inline fn キーワードを使って関数をインライン展開できます。また、関数を値として変数に代入したり引数として渡したりする「関数ポインタ」の仕組みも備えています。ここでは、インライン関数と関数を値として扱う方法を解説します。
構文
// -----------------------------------------------
// inline fn — 関数をインライン展開します
// -----------------------------------------------
inline fn 関数名(引数名: 引数の型) 戻り値の型 {
return 式;
}
// inline fn は呼び出し箇所にコードを展開します
// 関数呼び出しのオーバーヘッドをなくしたい場合に使います
// -----------------------------------------------
// 関数ポインタ型 — 関数を値として扱います
// -----------------------------------------------
// 関数ポインタ型の書き方
const 変数名: *const fn(引数の型) 戻り値の型 = &関数名;
// 関数ポインタを引数として受け取る高階関数
fn 高階関数名(func: *const fn(引数の型) 戻り値の型, 引数名: 引数の型) 戻り値の型 {
return func(引数名);
}
// -----------------------------------------------
// comptime 関数ポインタ — コンパイル時に型を解決します
// -----------------------------------------------
fn 関数名(comptime func: fn(引数の型) 戻り値の型, 引数名: 引数の型) 戻り値の型 {
return func(引数名);
}
構文一覧
| 構文/キーワード | 概要 |
|---|---|
inline fn 名前() 型 { } | 関数をインライン展開します。呼び出し箇所にコードが直接埋め込まれるため、関数呼び出しのオーバーヘッドがなくなります。 |
*const fn(型) 型 | 関数ポインタ型を表します。関数を変数に代入したり引数として渡したりできます。 |
&関数名 | 関数の参照(関数ポインタ)を取得します。変数や引数への代入に使います。 |
func(引数) | 関数ポインタを通じて関数を呼び出します。通常の関数呼び出しと同じ構文です。 |
comptime func: fn(...) ... | コンパイル時に関数が確定する引数を宣言します。インライン展開と組み合わせて使います。 |
callconv(.Inline) | 関数に呼び出し規約を明示的に指定する構文です。inline fn と同等の効果を持ちます。 |
サンプルコード
inline_function.zig
// inline_function.zig — inline fn と関数ポインタのサンプルです
// 龍が如くのキャラクターを使って
// インライン展開・関数を値として扱う方法を確認します
// 標準ライブラリをインポートします
const std = @import("std");
// -----------------------------------------------
// inline fn — インライン展開される関数です
// 呼び出し箇所にコードが直接埋め込まれます
// 短い処理や頻繁に呼ばれる処理に適しています
// -----------------------------------------------
// 桐生一馬の戦闘力を「龍の魂」補正で強化します(インライン関数)
inline fn kiryu_boost(power: u32) u32 {
// 乗算はシンプルな処理なので inline fn に向いています
return power * 3;
}
// 真島吾朗の移動速度を「狂犬」補正で加算します(インライン関数)
inline fn majima_speed(base: u32) u32 {
return base + 50;
}
// -----------------------------------------------
// 通常の関数(関数ポインタとして渡すために定義します)
// -----------------------------------------------
// 澤村遥の応援メッセージを出力する関数です
fn haruka_cheer(power: u32) u32 {
// 応援補正として +100 を加算します
return power + 100;
}
// 錦山彰の奥義補正を適用する関数です
fn nishiki_combo(power: u32) u32 {
// コンボ補正として 2 倍にします
return power * 2;
}
// 伊達俊夫の刑事スキルで防御力に換算する関数です
fn date_defense(power: u32) u32 {
// 半分を防御力として返します
return power / 2;
}
// -----------------------------------------------
// 高階関数 — 関数ポインタを引数として受け取ります
// *const fn(u32) u32 が関数ポインタ型の書き方です
// -----------------------------------------------
fn applySkill(
name: []const u8,
base_power: u32,
skill: *const fn (u32) u32, // 関数ポインタを引数に取ります
) u32 {
const result = skill(base_power); // 関数ポインタを通じて呼び出します
const stdout = std.io.getStdOut().writer();
stdout.print(" {s}: 基礎値 {d} → スキル適用後 {d}\n", .{ name, base_power, result }) catch {};
return result;
}
// -----------------------------------------------
// プログラムのエントリポイント
// -----------------------------------------------
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("=== 龍が如く スキルシステム ===\n\n", .{});
// ① inline fn の使用例です
// kiryu_boost() は呼び出し箇所にコードが展開されます
try stdout.print("--- inline fn デモ ---\n", .{});
const kiryu_base: u32 = 500;
const kiryu_powered = kiryu_boost(kiryu_base); // インライン展開されます
try stdout.print(" 桐生一馬: 基礎値 {d} → 龍の魂補正後 {d}\n", .{ kiryu_base, kiryu_powered });
const majima_base: u32 = 420;
const majima_powered = majima_speed(majima_base); // インライン展開されます
try stdout.print(" 真島吾朗: 基礎値 {d} → 狂犬補正後 {d}\n\n", .{ majima_base, majima_powered });
// ② 関数ポインタを変数に代入する例です
// *const fn(u32) u32 が関数ポインタ型です
try stdout.print("--- 関数ポインタ デモ ---\n", .{});
// &関数名 で関数ポインタを取得して変数に代入します
const skill_haruka: *const fn (u32) u32 = &haruka_cheer;
const haruka_result = skill_haruka(300); // 関数ポインタを通じて呼び出します
try stdout.print(" 澤村遥(関数ポインタ経由): 300 → {d}\n\n", .{haruka_result});
// ③ 関数ポインタを配列に格納して切り替える例です
// 3人のキャラクターのスキル関数を配列に並べます
try stdout.print("--- 関数ポインタ配列デモ ---\n", .{});
const names = [_][]const u8{ "澤村遥", "錦山彰", "伊達俊夫" };
const skills = [_]*const fn (u32) u32{ &haruka_cheer, &nishiki_combo, &date_defense };
const base_powers = [_]u32{ 300, 480, 260 };
// for 文でスキル関数を順に呼び出します
for (names, skills, base_powers) |name, skill, base| {
const result = skill(base); // 配列内の関数ポインタを呼び出します
try stdout.print(" {s}: {d} → {d}\n", .{ name, base, result });
}
try stdout.print("\n", .{});
// ④ 高階関数に関数ポインタを渡す例です
// applySkill() の第3引数に &関数名 を渡します
try stdout.print("--- 高階関数デモ ---\n", .{});
_ = applySkill("桐生一馬(応援補正)", kiryu_base, &haruka_cheer);
_ = applySkill("錦山彰(コンボ補正)", 480, &nishiki_combo);
_ = applySkill("伊達俊夫(防御換算)", 260, &date_defense);
}
zig run inline_function.zig === 龍が如く スキルシステム === --- inline fn デモ --- 桐生一馬: 基礎値 500 → 龍の魂補正後 1500 真島吾朗: 基礎値 420 → 狂犬補正後 470 --- 関数ポインタ デモ --- 澤村遥(関数ポインタ経由): 300 → 400 --- 関数ポインタ配列デモ --- 澤村遥: 300 → 400 錦山彰: 480 → 960 伊達俊夫: 260 → 130 --- 高階関数デモ --- 桐生一馬(応援補正): 基礎値 500 → スキル適用後 600 錦山彰(コンボ補正): 基礎値 480 → スキル適用後 960 伊達俊夫(防御換算): 基礎値 260 → スキル適用後 130
概要
『Zig』の inline fn は、関数を呼び出し箇所にコードとして直接展開する指示です。通常の関数呼び出しではスタックフレームの生成や引数の受け渡しにコストがかかりますが、inline fn を使うとそのオーバーヘッドがなくなります。サンプルの kiryu_boost() や majima_speed() のような短い算術処理に適しています。関数ポインタ型は *const fn(引数の型) 戻り値の型 と書き、&関数名 で関数ポインタを取得します。取得したポインタは変数に代入したり、applySkill() のような高階関数の引数として渡したりできます。また、配列に格納することで実行時に呼び出す関数を切り替えることも可能です。関数の基本については 関数の基本 を、エラーを返す関数については エラーを返す関数 も合わせて確認してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。