Reputation: 917
I have a generic structure I want to store a closure in. This closure's parameter and return types is directly related to the structure's final type. How can I define such a structure?
The only way I know how is to composite types using the where
keyword. However when attempting to compile the code, the compiler halts and complains that T
and 't
are not used.
I could get it to compile by adding useless variables that use T
and 't
, but I imagine that there is a better, more correct why to do this.
The following code (playpen) compiles. Remove the useless variables and it won't:
pub struct GenericContainer<'t, T: 't, F> where F: Fn(&'t [T]) -> Option<&'t [T]> {
generic_closure: F,
unused: Option<&'t T>
}
impl<'t, T: 't, F> GenericContainer<'t, T, F> where
F: Fn(&'t [T]) -> Option<&'t [T]> {
pub fn new(gc: F) -> Self {
GenericContainer {
generic_closure: gc,
unused: None
}
}
pub fn execute(&self, slice: &'t [T]) -> Option<&'t [T]> {
let g = &self.generic_closure;
let _ = &self.unused;
g(slice)
}
}
fn main() {
let g = GenericContainer::new(|s| if s.len() == 0 {None} else {Some(&s[..1])});
assert!(g.execute(b" ") == Some(b" "));
println!("ok");
}
Upvotes: 2
Views: 80
Reputation: 14992
You are in a typical "higher-ranked-stuff" situation: 't
and T
are only used to define the type F
.
First, for the lifetime, you can use the higher-ranked-lifetimes syntax of rust:
where F: for<'t> Fn(&'t [T]) -> Option<&'t [T]>
and thus remove it from you struct type.
It would be nice to do something similar for T
, but higher-ranked-types are currently not supported by Rust. So you best catch is probably to follow the suggestion of the compiler, and use std::maker::PhantomData
You end up with a type like:
pub struct GenericContainer<T, F>
where F: for<'t> Fn(&'t [T]) -> Option<&'t [T]>
{
generic_closure: F,
_marker: ::std::marker::PhantomData<T>
}
Note that prefixing _marker
with _
prevents it to be detected as unused.
Then, you just need to update your implementation:
impl<T, F> GenericContainer<T, F> where
F: for<'t> Fn(&'t [T]) -> Option<&'t [T]> {
pub fn new(gc: F) -> Self {
GenericContainer {
generic_closure: gc,
_marker: ::std::marker::PhantomData
}
}
pub fn execute<'t>(&self, slice: &'t [T]) -> Option<&'t [T]> {
let g = &self.generic_closure;
g(slice)
}
}
Upvotes: 3