// Generate a `build` method to go from builder to original struct.
//
// This method should require that every one of the fields has been explicitly
// set; it should return an error if a field is missing. The precise error type
// is not important. Consider using Box<dyn Error>, which you can construct
// using the impl From<String> for Box<dyn Error>.
//
// impl CommandBuilder {
// pub fn build(&mut self) -> Result<Command, Box<dyn Error>> {
// ...
// }
// }
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());
let command = builder.build().unwrap();
assert_eq!(command.executable, "cargo");
}
如提示所言,我們這一關主要的是實現build
方法,同時注意返回結果型別為Result
。
原來的資料我們設定在了XBuilder
中,這一關就需要從XBuilder
中反向注入引數了。
這裡需要擴充套件的是,一般操作過程錯誤處理需要返回
Result
。
並且對於一個Command
而言,可以有一些預設引數。
在這裡,我們將檢查全部欄位,如果沒有設定,返回異常。
雖然這裡沒有對異常進行檢查,但是後續的問題中,對異常的檢查會十分嚴格。
pub(super) fn solution(
fields: &crate::common::FieldsType,
builder_ident: &syn::Ident,
origin_ident: &syn::Ident,
) -> proc_macro2::TokenStream {
let idents: Vec<_> = fields.iter().map(|f| &f.ident).collect();
quote::quote! {
impl #builder_ident {
pub fn build(&self) -> std::result::Result<#origin_ident, std::boxed::Box<dyn std::error::Error>> {
// 異常檢查展開
#(
if self.#idents.is_none() {
let err = std::format!("field {} missing", std::stringify!(#idents));
return std::result::Result::Err(err.into());
}
)*
// 數值回傳
let res = #origin_ident {
#(
#idents: self.#idents.clone().unwrap()
),*
};
std::result::Result::Ok(res)
}
}
}
}
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 solution3_stream = solution35::soultion(fields, builder_ident);
token_stream.extend(solution3_stream);
// solution4
let solution45_stream = solution4::solution(fields, builder_ident, origin_ident);
token_stream.extend(solution45_stream);
proc_macro::TokenStream::from(token_stream)
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結