それに直面しましょう; オプションの名前付きパラメーターにより、Python は Rust のような他の多くのプログラミング言語よりも優れています。ただし、Rust ライブラリの作成者は、ビルダー パターンを使用してこの欠点に非常に効率的に対処できます。このパターンの背後にある考え方は、一見単純です。すべての値を保持できる (必須ではない) オブジェクトを作成し、すべての必須フィールドが存在するときに型を作成します。
この記事では、Rust のビルダー パターン、 Windows 向けの 30 のベスト コード エディターについて説明します。
ビルダーモード
可変参照を持つコンストラクター
Into および AsRef トレイト
デフォルト
型の状態を使用してコレクション フィールドを追跡する
Rust Builder パターン クレート
ビルダーモード
Rust のビルダー パターンを理解するために、Windows 10/11 で YouTube にログインできない問題を修正するために、まずビルダーを使用した場合と使用しない場合でコードがどのように見えるかを比較してみましょう。
// ビルダーなし
let base_time = DateTime::now();
させますflux_capacitor = FluxCapacitor::new();
let mut option_load = None;
let mut mr_fusion = なし;
な
if get_energy_level(&プルトニウム) > 1.21e9 {
option_load = Some(plutonium.rods());
} それ以外 {
// エネルギー源が必要です。失敗する可能性があります
mr_fusion = gets_mr_fusion(base_time).ok();
}
な
TimeMachine::new(
フラックスコンデンサ、
base_time、
オプション_ロード、
mr_fusion、
)
// ビルダーで
let builder = TimeMachineBuilder::new(base_time);
.flux_capacitor(FluxCapacitor::new());
な
if get_energy_level(&プルトニウム) > 1.21e9 {
builder.plutonium_rods(プルトニウム.rods())
} それ以外 {
builder.mr_fusion()
}
。建てる()
この本のすべての例は、単純になるように設計されています。実際、Windows 10でシステム割り込み100CPUを修正する方法は? 高い CPU 使用率の問題を軽減する方法 より多くの依存関係を持つ複雑な型にはビルダーを使用します。
ビルダーの主な機能は、インスタンスの構築に必要なデータを 1 か所に保存することです。TimeMachineBuilder 構造体を定義し、一連のフィールドを配置し、 と メソッド、およびいくつかのセッターを追加するだけで完了です。以上で、ビルダーについて知っておくべきことがすべてわかりました。またね!オプション<_>implnewbuild
あなたはまだここにいるの?ああ、だまされるとは思えない。もちろん、ビルダー向けのMicrosoft Store エラー 0x80073CFB を修正する方法は、明らかなデータ収集だけではありません。
可変参照を持つコンストラクター
一部のガベージ コレクション言語とは異なり、Rust では所有値と借用値を区別します。したがって、ビルダー メソッドを設定するにはさまざまな方法があります。1 つは変数参照によって取得され、もう1 つは値によって取得されます。前者には、return link と . allow link の 2 つのサブバリアントがあり、どちらがより一般的です。&自分をミュート&自分をミュート()
この例では、リンクを使用しているため、値によるジェネレーターを使用しています。new の結果は、別のメソッドを呼び出すために直接使用されます。
ミュータブルな借用ビルダーの利点は、同じビルダーで複数のメソッドを呼び出しながら、いくつかのチェーンを許可できることです。ただし、これには、ビルダー設定へのバインドが必要になるという代償が伴います。たとえば、Zoom が登録できない問題を修正するにはどうすればよいですか? Zoom は登録エラーとその背後にある理由を登録する資格がありません。次のコードは return メソッドで失敗します: &mut self
let builder= ByMutRefBuilder::new()
.with_favorite_number(42); // これにより、借用中にビルダーが削除されます
ただし、完全なチェーンを実行しても機能します。
ByMutRefBuilder::new()
.with_favorite_number(42)
.with_favorite_programming_language("Rust")
。建てる()
ビルダーを再利用したい場合は、呼び出しの結果をバインドする必要があります: new()
let mut ビルダー = ByMutRefBuilder::new();
builder.with_favorite_number(42) // これは、さらなる連鎖のために `&mut builder` を返します
チェーンを無視して、代わりに同じバインディングを複数回呼び出すこともできます。
let mut ビルダー = ByMutRefBuilder::new();
builder.with_favorite_number(42);
builder.with_favorite_programming_language("Rust");
ビルダー.ビルド()
一方、値によるビルダーは、状態を破棄しないために再バインドが必要です。
let builder = ByValueBuilder::new();
builder.with_favorite_number(42); // これはビルダーを消費します :-(
したがって、それらは通常連鎖しています。
ByValueBuilder::new()
.with_favorite_number(42)
.with_favorite_programming_language("Rust")
。建てる()
したがって、値によるビルダーの場合、連鎖が必要です。一方、変数参照用のWindows 10 ビルダーの 50 の無料ゲーム ダウンロードでは、ビルダー自体が何らかのローカル変数にバインドされている限り、連鎖が許可されます。また、変更可能な参照のビルダーは、メソッドによって消費されないため、自由に再利用できます。
一般に、連鎖はビルダーを使用するための意図された方法であるため、これは大きな欠点ではありません。また、ビルダーに含まれるデータの量によっては、モバイル ビルダーがパフォーマンス プロファイルに表示される場合がありますが、これはまれです。
多くのブランチを持つ複雑なコードでビルダーが頻繁に使用される場合、Windows 10 がロックアップし続ける場合はどうなりますか? または、中間状態から再利用される可能性があります。私は、変更可能な参照ビルダーを好みます。それ以外の場合は、ジェネレーターを値渡しで使用します。
Into および AsRef トレイト
もちろん、ビルダー メソッドはいくつかの基本的な変換を行うことができます。最も一般的なものは、 Into トレイトを使用して入力をバインドします。
たとえば、実装のあるものとしてインデックスを作成したり、PC 上の Google Chrome で CPU とメモリの使用率が高くなるのを修正したり、ビルダーがパラメーターを使用して割り当てを削減できるようにしたりして、関数が a と の両方を受け入れるようにすることができます。与えられた引数、特性は、提供された型でより多くの自由を許可できます。Into<usize>Into<Cow<'static, str>>&'static strStringAsRef
IntoIterator や ToString などの特殊な特性もあり、Windows 10 で Skype の高い CPU 使用率を修正するのに役立つ場合があります。たとえば、値の配列がある場合、各 Vec 内で add_all を拡張する add メソッドを使用できます。
impl FriendlyBuilder {
fn add(&mut self, value: impl Into<String>) -> &mut Self {
self.values.push(value.into())
自己
}
な
fn add_all(
&mut 自分自身、
値: impl IntoIterator<Item = impl Into<String>>
) -> &mut 自己 {
self.values.extend(values.into_iter().map(Into::into));
自己
}
}
デフォルト
多くの場合、型には実行可能なデフォルト値があります。したがって、Windows 10 Builder で Spotify エラーを修正する 9 つの方法は、これらのデフォルトを事前に設定し、ユーザーが要求した場合にのみそれらを置き換えることができます。まれに、デフォルト値の取得にコストがかかる場合があります。ビルダーは、独自のデフォルト値 None を持つ Option を取るか、別のトリックを実行してどのフィールドが設定されているかを追跡できます。これについては次のセクションで説明します。
もちろん、Default の実装が提供するものには依存せず、独自のデフォルトを設定できます。たとえば、多いほど良いと判断できるので、デフォルトの数はゼロではなくゼロになります。u32::MAXDefault
参照カウントを含むより複雑な型の場合、静的なデフォルトがある場合があります。参照カウントの実行時のオーバーヘッドが小さいため、毎回取得します。あるいは、静的インスタンスの借用を許可する場合は、ビルドをシンプルに保ちながら、デフォルトを使用して割り当てを回避できます: Arc::clone(_)Cow < '静的、T>
std::sync::Arc を使用します。
static ARCD_BEHEMOTH: Arc<Behemoth> = Arc::new(Behemoth::dummy());
static DEFAULT_NAME: &str = "ふわふわ";
impl WithDefaultsBuilder {
fn new() -> 自己 {
自己 {
// 単純に `Default` を使用できます
some_defaulting_value: デフォルト::default(),
// もちろん、独自のデフォルトを設定できます
数: 42,
// 構築に不要な値の場合
optional_stuff: なし、
// `Cow` の場合、デフォルトを借りることができます
名前: 牛::借用(DEFAULT_NAME),
// `static` を複製できます
ゴリアテ: Arc::clone(ARCD_BEHHEMOTH),
}
}
}
型の状態を使用してコレクション フィールドを追跡する
追跡設定フィールドは、所有するバリアントでのみ使用できます。アイデアは、ジェネリックスを使用して、どのフィールドが設定されているかに関する情報を型に入れることです。したがって、二重設定を回避できます。実際には、それらを禁止して、すべての必須フィールドが設定されている場合にのみビルドを許可することもできます。
お気に入りの数字、プログラミング言語、色を例に取りましょう。最初のものだけが必要です。私たちの型は、数値が設定されているかどうか、プログラミング言語が設定されているかどうか、色が設定されているかどうかを示します。TypeStateBuilder<N, P, C>NPC
その後、Unset 型と Set 型を作成して、ジェネリックを設定できます。新しい関数が戻り、 a のみがメソッドを持ちます。TypeStateBuilder<Unset, Unset, Unset>TypeStateBuilder<Set, _, _>.build()
この例では、安全でないコードを使用するとスキーマの理解に役立たないため、すべての場所で既定値を使用しています。ただし、もちろん、このスキームを使用して不要な初期化を回避できます。
std::marker::PhantomData を使用します。
/// 設定フィールドを表す型
列挙セット {}
/// 設定されていないフィールドを表す型
enum 未設定 {}
/// 私たちのビルダー。この場合、裸の型を使用しました。
struct<N, P, C> TypeStateBuilder<N, P, C> {
番号:u32、
プログラミング言語: 文字列、
色: 色、
typestate: PhantomData<(N, P, C)>,
}
/// `new` 関数はすべてのフィールドを未設定のままにします
impl TypeStateBuilder<未設定、未設定、未設定> {
fn new() -> 自己 {
自己 {
数: 0,
プログラミング言語: "",
色: 色::default(),
typestate: ファントムデータ、
}
}
}
/// `.with_favorite_number(_)` は 1 回しか呼び出せません
impl<P, C> TypeStateBuilder<Unset, P, C> {
fn with_favorite_number(
自己、
番号:u32、
) -> TypeStateBuilder<セット、P、C> {
TypeStateBuilder {
番号、
プログラミング言語: self.programming_language,
色: 自己.色,
typestate: ファントムデータ、
}
}
}
impl<N, C> TypeStateBuilder<N, Unset, C> {
fn with_favorite_programming_language(
自己、
プログラミング言語: &'static str,
) -> TypeStateBuilder<N, セット, C> {
TypeStateBuilder {
番号: 自己番号,
プログラミング言語、
色: 自己.色,
typestate: ファントムデータ、
}
}
}
impl<N, P> TypeStateBuilder<N, P, Unset> {
fn with_color(self, color: Color) -> TypeStateBuilder<N, P, Set> {
TypeStateBuilder {
番号: 自己番号,
プログラミング言語: self.programming_language,
色、
typestate: ファントムデータ、
}
}
}
/// 実際には、これはのすべてのバリアントに特化されます
/// `Set`/`Unset` タイプ状態
impl<P, C> TypeStateBuilder<セット, P, C> {
fn build(self) -> お気に入り {
全て!()
}
}
インターフェイスは値渡しビルダーとまったく同じように機能しますが、これらのケースを実装するために追加された場合、ユーザーはフィールドを 1 回または複数回しか設定できません。どの関数がどの順序で呼び出されるかを制御することもできます。たとえば、 が呼び出されて typestate が空にコンパイルされた後にのみ許可できます。.with_favorite_programming_language( ).with_favorite_number( )
これの欠点は明らかに複雑で、誰かがコードを書く必要があり、コンパイラはそれを解析して最適化する必要があります。したがって、関数呼び出しの順序を実際に制御するため、または最適化された初期化を可能にするために typestate を使用しない限り、おそらく良い投資ではありません。
Rust Builder パターン クレート
ビルダーはこのような単純なコード パターンに従うため、自動的に生成される多くのクレートが crates.io にあります。
serve_builder クレートは、カスタムからの引数とオプションのデフォルト値を使用して、標準の変更可能な参照ビルダーをビルドします。検証機能を提供することもできます。これは、ビルダーを自動的に生成する最も一般的な proc マクロ クレートであり、適切な選択です。これを書いている時点で、クレートは 6 年前のものなので、これは fork-stable 以来の最初のフォーク クレートの 1 つです。インストラクト
上記のように、typed-builder クレートは値による型状態の実装全体を処理するため、今読んだ内容をすべて忘れることができます。コードを入力するだけで、タイプ セーフなビルダーを利用できます。また、デフォルトおよびオプションのアノテーションがあり、常に任意の値を取得して設定するセッター メソッドを使用できるアノテーションがあります。cargo add typed-builderintostrip_optionSome(値)
safe-builder-derive クレートも型状態を実装しますが、set/unset フィールドの組み合わせごとに型状態の impl を生成することで、指数関数的に増加するコードにつながります。最大 3 つまたは 4 つのフィールドを持つ小規模なビルダーの場合、これはまだ受け入れ可能な選択である可能性があります。
tidy-builder クレートは基本的に typed-builder と同じですが、typestate 用です。buildstructor クレートも typed-builder に触発されていますが、構造体の代わりに注釈付きコンストラクターを使用しています。builder-pattern クレートも型状態パターンを使用し、遅延デフォルトと検証関数に注釈を付けることができます。〜定数ブール
今後も増えることは間違いありません。コードで自動生成されたビルダーを使用したい場合、それらのほとんどは良い選択だと思います。いつものように、走行距離は異なる場合があります。たとえば、Into パラメーターに注釈を要求することは、一部の人にとってはより人間工学的かもしれませんが、他の人にとっては複雑さを軽減します。認証が必要なユースケースもあれば、役に立たないユースケースもあります。
結論は
ビルダーは、Rust の名前付きおよびオプションのパラメーターの欠如を簡単に補うことができ、コンパイル時および実行時にそれらを自動的に変換および検証することさえできます。さらに、このパターンはほとんどの開発者にとって馴染み深いものであるため、ユーザーはすぐに慣れることができます。
いつものように、欠点は保守とコンパイルのための余分なコードです。派生クレートは、コンパイル時間の別の部分を犠牲にして、メンテナンスの負担を取り除くことができます。
では、すべてのタイプにビルダーを使用する必要がありますか? 個人的には、少なくとも 5 つの部分または複雑な相互依存関係を持つ型にのみ使用しますが、これらの場合は不可欠だと考えています。