I have written a filter_book function taht checks a book against a fitler and returns a boolean. No problem in and of itself. But I wondering if there is a more idiomatic way to write it with better short circuit. Slightly simplified, body starts with:
let mut val = filter.name.is_empty() || book.name.contains(filter.name());
I could then do
if !val { return false };
but if I do that, I end up doing it over and over again.
The rest of the function (until the ending return of val) consists of a series of liens that look like:
val &= (filter.field.is_empty() || book.afield.contains(filter.field));
Is there a better way to structure that? I presume that even if there were a syntactic way to short-circuit it, the result would actually cause a lot more checks for exiting, since I expect most of the fitler fields to be empy, and therefore succeed?
Thanks,
Joel
If every filter.field has the same type and every book.afield has the same type (not necessarily the same as the filter.field type), you can sort of simplify this with a loop over an array of pairs of references, like so:
let fields = [
(&filter.name, &book.name),
(&filter.author, &book.author),
(&filter.subject, &book.subject),
// etc.
];
for (filtfield, bookfield) in fields {
if !(filtfield.is_empty() || bookfield.contains(filtfield)) {
return false;
}
}
return true;
or, with iterator methods:
let fields = [
(&filter.name, &book.name),
(&filter.author, &book.author),
(&filter.subject, &book.subject),
// etc.
];
return fields.into_iter().all(|(filtfield, bookfield)| filtfield.is_empty() || bookfield.contains(filtfield));
let mut ok = long_line_testing_something();
ok = ok && long_line_testing_something_other();
ok = ok && (long_test_a() || long_test_b());
ok = ok && {
let mut or = i_run_out_of_names();
or = or || maybe_this_is_not_a_good_idea();
or || but_who_knows()
};
ok = ok && here_we_continue();
ok = ok && until_nobody_understand_this_code();