[Rust] bitflagsマクロでビットフラグ管理

2022.05.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Introduction

bitflagsはビットフラグを簡単に定義することができるマクロを
提供してくれるcrateです。
複数のフラグ管理をシンプルにしてくれます。

Environment

  • MacBook Pro (13-inch, M1, 2020)
  • OS : MacOS 11.3.1
  • rust : 1.60.0

Try

cargo new でプロジェクトをつくったら
Cargo.tomlに依存ライブラリを記述します。

[dependencies]
bitflags = "1.3.2"

マクロ(bitflags!)をつかって複数のフラグを管理する構造体として定義します。
↓ではu32型の変数1つでA,B,Cの3つのフラグを管理します。

use bitflags::bitflags;

bitflags! {
    pub struct Flags: u32 {
        const A = 0b00000001;
        const B = 0b00000010;
        const C = 0b00000100;
    }
}

普通に変数に代入して比較したり、
containsで対象のフラグが含まれているかチェックできます。

let flag = Flags::A;
assert_eq!(flag, Flags::A);
assert_eq!(flag.contains(Flags::A), true);

複数のフラグもセットできます。
それぞれの変数で&をとったり引き算したりできます。

//複数フラグセット
let flag_1 = Flags::A | Flags::C;
let flag_2 = Flags::B | Flags::C;

assert_eq!((flag_1 & flag_2), Flags::C);
assert_eq!((flag_1 -flag_2), Flags::A);
assert_eq!(!flag_2, Flags::A);

実際の値を表示するにはbitsを使いましょう。

println!("{:#010b}", Flags::A.bits);// 0b00000001
println!("{:#010b}", Flags::B.bits);// 0b00000010
println!("{:#010b}", Flags::C.bits);// 0b00000100

println!("{:#010b}", flag.bits);//0b00000001
println!("{:#010b}", flag_1.bits);//0b00000101
println!("{:#010b}", flag_2.bits);//0b00000110

removeとinsertでフラグの変更。

let mut flag:Flags = Flags::A;
assert_eq!(flag, Flags::A);

flag = Flags::A | Flags::C;
assert_eq!(flag, Flags::A | Flags::C);
assert_eq!(flag & Flags::A, Flags::A);
assert_eq!(flag & Flags::C, Flags::C);

//remove
flag.remove(Flags::C);
assert_eq!(flag.contains(Flags::A), true);
assert_eq!(flag.contains(Flags::B), false);
assert_eq!(flag.contains(Flags::C), false);

//insert
flag.insert(Flags::C);
assert_eq!(flag.contains(Flags::A), true);
assert_eq!(flag.contains(Flags::B), false);
assert_eq!(flag.contains(Flags::C), true);

all関数ですべてのフラグをたてることができる。

let all_flag = Flags::all();
println!("{:#010b}", all_flag.bits);//0b00000111

簡単な説明は以上です。
これ以外にも機能があるので、ドキュメントをご確認ください。

Summary

bitflagsマクロを使うと、普通にやるよりシンプルにフラグ管理ができます。
boolで8つのフラグを構造体で定義したら8bit必要ですが、
bitflagsでu32のフラグを使えば4bitで管理できます。
無駄なリソースも使わず、安全に計算できたりもするので楽ですね。

References