// Generate methods on the builder for setting a value of each of the struct
// fields.
//
// impl CommandBuilder {
// fn executable(&mut self, executable: String) -> &mut Self {
// self.executable = Some(executable);
// self
// }
//
// ...
// }
use derive_builder::Builder;
#[derive(Builder)]
pub struct Command {
executable: String,
args: Vec<String>,
env: Vec<String>,
current_dir: String,
}
fn main() {
let mut builder = Command::builder();
builder.executable("cargo".to_owned());
builder.args(vec!["build".to_owned(), "--release".to_owned()]);
builder.env(vec![]);
builder.current_dir("..".to_owned());
}
這道題清晰明瞭,主要是為XXBuilder
實現各種的setter
方法。
相關的模板和fields
之前都已經獲取好了,這裡直接實現就行了。
值的注意的是,實現
setter
方法的時候經常會進行鏈式呼叫。
雖然用例裡面都是分開呼叫的,但是在第五關的用例中,會進行鏈式呼叫
use derive_builder::Builder;
#[derive(Builder)]
pub struct Command {
executable: String,
args: Vec<String>,
env: Vec<String>,
current_dir: String,
}
fn main() {
let command = Command::builder()
.executable("cargo".to_owned())
.args(vec!["build".to_owned(), "--release".to_owned()])
.env(vec![])
.current_dir("..".to_owned())
.build()
.unwrap();
assert_eq!(command.executable, "cargo");
}
因此,在實現的時候順便返回自身物件的引用,合二為一更方便。
// solution35.rs
pub(super) fn soultion(
fields: &crate::common::FieldsType,
builder_ident: &syn::Ident,
) -> proc_macro2::TokenStream {
let idents: Vec<_> = fields.iter().map(|f| &f.ident).collect();
let tys: Vec<_> = fields.iter().map(|f| &f.ty).collect();
quote::quote! {
impl #builder_ident {
#(
pub fn #idents(&mut self, #idents: #tys) -> &mut Self {
self.#idents = std::option::Option::Some(#idents);
// 返回自身引用,順便解決第五題鏈式呼叫
self
}
)*
}
}
}
可以看到,除了基本的模板,我們主要依靠解析的資訊讓單一的模板多樣化。
// lib.rs
mod solution2;
mod solution35;
fn solution1(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
let fields = {
match common::parse_fields(&ast) {
Ok(f) => f,
Err(_e) => std::panic!(std::stringify!(_e)),
}
};
let origin_ident = &ast.ident;
let builder_ident = "e::format_ident!("{}Builder", origin_ident);
let mut token_stream = proc_macro2::TokenStream::new();
// solution2
let solution2_stream = solution2::solution(fields, origin_ident, builder_ident);
token_stream.extend(solution2_stream);
// solution35
let solution35_stream = solution35::soultion(fields, builder_ident);
token_stream.extend(solution35_stream);
proc_macro::TokenStream::from(token_stream)
本作品採用《CC 協議》,轉載必須註明作者和本文連結