blockの巣

【Nigtly Rust】コンパイル時と実行時で処理を呼び分けるconst_eval_select

2026/04/21 01:59 公開
Nightly Rust

この記事は2026-04-19のnightlyビルドで動作の確認をしています

const_eval_selectとは

コンテキスト(constコンテキストかどうか)によって呼び出す関数を切り替えられるようにするための機能です。

std::intrinsics::const_eval_select

使い方

const_eval_select(関数に渡す引数, コンパイル時に呼び出す関数, 実行時に呼び出す関数) のように使用します。
const_eval_select(args, const_fn, runtime_fn)のようにすることで、
コンパイル時には const_fn(args)、実行時には const_fn(args)に置き換えられます。
第一引数に渡すのは第二、第三引数に渡す関数の呼び出しに使用する引数のタプルです。

平方根を求める関数(sqrt)をコンパイル時にも使えるようにするための例です。
実行時にはf64のsqrtを呼び出しますが、コンパイル時にはニュートン法を用いて平方根を求める関数を呼び出すようにしています。

#![feature(core_intrinsics)]
#![feature(const_eval_select)]

use std::intrinsics::const_eval_select;

// コンパイル時に呼び出される関数
const fn ct_sqrt_f64(x: f64) -> f64 {
    if x < 0.0 {
        return f64::NAN;
    }
    if x == 0.0 {
        return 0.0;
    }
    let mut guess = x / 2.0;
    loop {
        let new_guess = 0.5 * (guess + (x / guess));
        if (guess - new_guess).abs() < 1e-10 {
            break new_guess;
        }
        guess = new_guess;
    }
}

// 実行時に呼び出される関数
fn rt_sqrt_f64(x: f64) -> f64 {
    x.sqrt() // f64のsqrtを呼ぶ
}

// 呼び分けを行うラッパー関数
pub const fn sqrt(x: f64) -> f64 {
    // 引数のタプル, コンパイル時関数, 実行時関数を渡す
    const_eval_select((x,), ct_sqrt_f64, rt_sqrt_f64)
}

呼び出し側は通常の関数呼び出しのように使うことができます。

fn main() {
    const COMPILE_TIME_RESULT: f64 = sqrt(2.0);
    println!("Compile-time sqrt(2.0) = {}", COMPILE_TIME_RESULT);

    let runtime_result = sqrt(2.0);
    println!("Runtime sqrt(2.0) = {}", runtime_result);
}

Rust Playgroundで実行する

注意点

const_eval_selectに渡す2つの関数は、同じ引数を取り同じ型の値を返す必要があります。

またcore_intrinsicsを有効にすることで以下の警告が出ます。

warning: the feature `core_intrinsics` is internal to the compiler or standard library
 --> src/main.rs:1:12
  |
1 | #![feature(core_intrinsics)]
  |            ^^^^^^^^^^^^^^^
  |
  = note: using it is strongly discouraged
  = note: `#[warn(internal_features)]` on by default

core_intrinsicsはコンパイラもしくは標準ライブラリの内部機能です」という警告で、おそらくユーザー側で使用することは推奨されていないです。
どうしても使用したい場合は警告を抑制して使用することになると思います。

まとめ