🤏
コンパイル時に型のサイズを確認する
コンパイルタイムに型のサイズをassertしたいときに以下のような方法が使える
SizeCheck struct
const関数がコンパイル時に評価されるのを使ってこのようなコードが書ける。
struct SizeCheck<T, const N: usize>(PhantomData<T>);
impl<T, const N: usize> SizeCheck<T, N> {
const OK: () = assert!(size_of::<T>() <= N);
}
SizeCheckは型TのPhantomDataとサイズチェックに使う値の二つのジェネリクスパラメータを持つ。
SizeCheckに対して、コンパイル時に評価される定数OKを実装することでコンパイル時サイズチェックを実現できる。
これを使ってこのようなコードを考えてみる。
struct Small {
_data: [u8; 32]
}
struct Large {
_data: [u8; 1024]
}
fn main(){
SizeCheck::<Small, 256>::OK;
SizeCheck::<Large, 256>::OK;
}
Smallはサイズが256バイト以下なのでコンパイルに成功するが、Largeはサイズが1024バイトなのでコンパイルに失敗する
このrust-playgroundで確認してみてほしい。
[追記]
kanarusさんにご指摘いただきました。このようなジェネリクスを用いなくてもconst _: () = assert!(size_of::<T> /* 条件 */);というような文をコードのどこかに入れるだけで目的が達成されるようです。文中のOKはasociated constというだけでコンパイル時に評価されるconst定数に値をバインドするようにすれば様々なコンパイル時評価が可能なようです。
Discussion
とありますが、
は associated const (関連定数) です
SizeCheck構造体を用意する必要もなくて、ソースコードのどこかにconst _: () = assert!(size_of::<T> /* 条件 */);を入れておけばよいです (以下の Playground で確認してみてください)const _: () = ...;みたいなやつを anon const (anonymous const) と呼んだりしますtrait境界やジェネリクスでどうにかすることばかり考えてしまっていましたね…constだけでも実現できるとは、constへの理解が深まりました。コメントありがとうございます!(それはそれとしてこの書き方はかっこいいので好きです)
(とりあえず、この
OKは関数ではないので、そこの表現だけ直しておかれた方がいいかと思います)const関連について内容修正し、追記しました。ご指摘ありがとうございます🙇♂️