My goal is to make the last 2 lines of this code compile and the last assertion to pass:
struct State {
string: String
}
impl State {
fn string<F: FnMut(String) -> String>(mut self, mut f: F) -> Self {
self.string = f(self.string);
self
}
}
fn main() {
let state = State { string: String::from("foo") };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
// let state = state.string(String::from("baz"));
// assert_eq!(state.string, "baz");
}
I thought this would be possible with traits and specialization, but the following code:
#![feature(specialization)]
trait Get<T> {
fn get(self, old: T) -> T;
}
impl<T> Get<T> for T {
default fn get(self, _: T) -> T {
self
}
}
impl<T, F> Get<T> for F where F: FnMut(T) -> T {
fn get(mut self, old: T) -> T {
self(old)
}
}
struct State {
string: String
}
impl State {
fn string<G: Get<String>>(mut self, g: G) -> Self {
self.string = g.get(self.string);
self
}
}
throws this error (live):
error[E0119]: conflicting implementations of trait `Get<_>`:
--> <anon>:13:1
|
13 | impl<T, F> Get<T> for F where F: FnMut(T) -> T {
| ^
|
note: conflicting implementation is here:
--> <anon>:7:1
|
7 | impl<T> Get<T> for T {
| ^
error: aborting due to previous error
So my question is, why is the second impl of Get not more "specific" than the first one, and is there any way in current stable or nightly Rust to get my original code to work?
Edit: I know implementing a trait for just one type would work, but I want a generic solution for any type as I want to be able to use this for any arbitrary fields of a struct.
FnMut is implemented automatically by closures which take mutable references to captured variables, as well as all types that implement Fn , e.g., (safe) function pointers (since FnMut is a supertrait of Fn ). Additionally, for any type F that implements FnMut , &mut F implements FnMut , too.
Parameter values can be passed by reference by prefixing the variable name with an & . In the example given below, we have a variable no, which is initially 5. A reference to the variable no is passed to the mutate_no_to_zero() function. The function operates on the original variable.
We define a function in Rust by entering fn followed by a function name and a set of parentheses. The curly brackets tell the compiler where the function body begins and ends. We can call any function we've defined by entering its name followed by a set of parentheses.
Use FnOnce as a bound when you want to accept a parameter of function-like type and only need to call it once. If you need to call the parameter repeatedly, use FnMut as a bound; if you also need it to not mutate state, use Fn .
For your concrete issue, you don't need specialization:
struct State {
string: String,
}
impl State {
fn string<F>(mut self, mut f: F) -> Self
where F: Thing
{
self.string = f.thing(self.string);
self
}
}
trait Thing {
fn thing(&mut self, s: String) -> String;
}
impl Thing for String {
fn thing(&mut self, _s: String) -> String {
self.clone()
}
}
impl<F> Thing for F
where F: FnMut(String) -> String
{
fn thing(&mut self, s: String) -> String {
(self)(s)
}
}
fn main() {
let state = State { string: String::from("foo") };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
let state = state.string(String::from("baz"));
assert_eq!(state.string, "baz");
}
You may either want to require FnOnce
or implement the trait for a &str
. Right now, the allocation of the String
is not being used, causing a bit of inefficiency.
You could then implement the trait multiple times for the interesting types:
struct State {
string: String,
vec: Vec<u8>,
}
impl State {
fn string<F>(mut self, mut f: F) -> Self
where F: Thing<String>
{
self.string = f.thing(self.string);
self
}
fn vec<F>(mut self, mut f: F) -> Self
where F: Thing<Vec<u8>>
{
self.vec = f.thing(self.vec);
self
}
}
trait Thing<T> {
fn thing(&mut self, s: T) -> T;
}
impl Thing<String> for String {
fn thing(&mut self, _s: String) -> String {
self.clone()
}
}
impl<F> Thing<String> for F
where F: FnMut(String) -> String
{
fn thing(&mut self, s: String) -> String {
(self)(s)
}
}
impl Thing<Vec<u8>> for Vec<u8> {
fn thing(&mut self, _s: Vec<u8>) -> Vec<u8> {
self.clone()
}
}
impl<F> Thing<Vec<u8>> for F
where F: FnMut(Vec<u8>) -> Vec<u8>
{
fn thing(&mut self, s: Vec<u8>) -> Vec<u8> {
(self)(s)
}
}
fn main() {
let state = State { string: String::from("foo"), vec: vec![1] };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
let state = state.string(String::from("baz"));
assert_eq!(state.string, "baz");
assert_eq!(state.vec, [1]);
let state = state.vec(|mut old: Vec<u8>| {
old.push(2);
old
});
assert_eq!(state.vec, [1, 2]);
let state = state.vec(vec![3]);
assert_eq!(state.vec, [3]);
}
I believe that repetition could be handled by a macro:
macro_rules! thing {
($t: ty) => {
impl Thing<$t> for $t {
default fn thing(&mut self, _val: $t) -> $t {
self.clone()
}
}
impl<F> Thing<$t> for F
where F: FnMut($t) -> $t
{
fn thing(&mut self, val: $t) -> $t {
(self)(val)
}
}
}
}
thing!(String);
thing!(Vec<u8>);
Specialization doesn't work here because specialization only works for chains. That is, there exist functions that satisfy the impl
impl<T, F> Get<T> for F where F: FnMut(T) -> T
but not
impl<T> Get<T> for T
so the latter cannot specialize the former.
The simplest way to fix this is to just write a GetString
trait instead of a Get<T>
trait; that way you don't have to consider specialization on such malarkey at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With