I'm relatively new to using Rust, and I'm using it for Advent of Code to help me learn. For the fourth problem, I want to create a lookup table using a HashMap to map from string keys to function values. I understand that Rust does not have syntactic sugar for creating HashMap literals so I am creating my HashMap from a slice. When I use fn function pointers it all works fine:
type ValidatorFn = fn(&str) -> bool;
...
let validation_rules: HashMap<&str, ValidatorFn> = [
("byr", validate_birth_year as ValidatorFn), // "as" cast is necessary here...
("iyr", validate_issue_year),
("eyr", validate_expiration_year),
("hgt", validate_height),
("hcl", validate_hair_colour),
("ecl", validate_eye_colour),
("pid", validate_passport_id),
]
.iter()
.cloned()
.collect();
However, this limits me to only being able to store functions defined with the fn
keyword and not closures. As an exercise I would like to rewrite my code to use boxed Fn
trait objects instead of fn
pointers to allow the use of closures or functions. However, my naive attempt to do so does not work:
type ValidatorFn = Box<dyn Fn(&str) -> bool>;
...
let validation_rules: HashMap<&str, ValidatorFn> = [
("byr", Box::new(validate_birth_year) as ValidatorFn),
("iyr", Box::new(validate_issue_year)),
("eyr", Box::new(validate_expiration_year)),
("hgt", Box::new(validate_height)),
("hcl", Box::new(validate_hair_colour)),
("ecl", Box::new(validate_eye_colour)),
("pid", Box::new(validate_passport_id)),
]
.iter()
.cloned()
.collect();
Gives multiple compiler errors:
error[E0277]: the trait bound `dyn for<'r> Fn(&'r str) -> bool: Clone` is not satisfied
--> src/main.rs:21:6
|
21 | .cloned()
| ^^^^^^ the trait `Clone` is not implemented for `dyn for<'r> Fn(&'r str) -> bool`
|
= note: required because of the requirements on the impl of `Clone` for `Box<dyn for<'r> Fn(&'r str) -> bool>`
= note: required because it appears within the type `(&str, Box<dyn for<'r> Fn(&'r str) -> bool>)`
error[E0599]: no method named `collect` found for struct `Cloned<std::slice::Iter<'_, (&str, Box<dyn for<'r> Fn(&'r str) -> bool>)>>` in the current
scope
--> src/main.rs:22:6
|
22 | .collect();
| ^^^^^^^ method not found in `Cloned<std::slice::Iter<'_, (&str, Box<dyn for<'r> Fn(&'r str) -> bool>)>>`
|
::: /Users/ryan/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/adapters/mod.rs:388:1
|
388 | pub struct Cloned<I> {
| -------------------- doesn't satisfy `_: Iterator`
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`Cloned<std::slice::Iter<'_, (&str, Box<dyn for<'r> Fn(&'r str) -> bool>)>>: Iterator`
which is required by `&mut Cloned<std::slice::Iter<'_, (&str, Box<dyn for<'r> Fn(&'r str) -> bool>)>>: Iterator`
Can someone help decipher this error message and let me know if what I'm trying to do is even possible? It seems to be telling me that either the Box or its contents cannot be cloned. I thought that a Box is basically just a pointer to somewhere on the heap though so I don't understand why that cannot be cloned?