How can I implement std :: convert :: From so that it does not consume its input?

I managed to do a check like Rust in an infinite loop. A very similar program compiles without problems. Why is the program that I do not want to compile?

To save you time and effort, I made minimal versions of two programs that isolate the problem. Of course, the minimal version is a pointless program. You will need to use your imagination to see my motivation.

Success

Let me start with a version that works. Pattern F<T> wraps T Target type can be converted from F<T> provided that T can.

 struct F<T>(T); impl<T> From<F<T>> for Target where Target: From<T> { fn from(a: F<T>) -> Target { let b = Target::from(a.0); f(&b) } } 

Here's an example of the caller:

 fn main() { let x = Target; let y = F(F(F(x))); let z = Target::from(y); println!("{:?}", z); } 

This one works and prints "Target" .

Renouncement

The f function does not use its argument. I would prefer that the From transformation also not use its argument, because the type F<T> may be expensive or impossible to clone. I can write a custom FromRef attribute that differs from std::convert::From by accepting an immutable loan instead of its value:

 trait FromRef<T> { fn from_ref(a: &T) -> Self; } 

Of course, I ultimately want to use From<&'a T> , but by defining my own trait, I can more clearly ask my question without interfering with the parameters of life. (The behavior of the check type is the same using From<&'a T> ).

Here is my implementation:

 impl<T> FromRef<F<T>> for Target where Target: FromRef<T> { fn from_ref(a: &F<T>) -> Target { let b = Target::from_ref(&a.0); f(&b) } } 

It compiles. However, the main() function does not matter:

 fn main() { let x = Target; let y = F(F(F(x))); let z = Target::from_ref(y); println!("{:?}", z); } 

This gives a huge start error message :

 error[E0275]: overflow evaluating the requirement `_: std::marker::Sized` --> <anon>:26:13 | 26 | let z = Target::from_ref(y); | ^^^^^^^^^^^^^^^^ | = note: consider adding a `#![recursion_limit="128"]` attribute to your crate = note: required because of the requirements on the impl of `FromRef<F<_>>` for `Target` = note: required because of the requirements on the impl of `FromRef<F<F<_>>>` for `Target` = note: required because of the requirements on the impl of `FromRef<F<F<F<_>>>>` for `Target` etc... 

What am I doing wrong?

Update

I accidentally fixed it !

The problem was that I forgot to implement FromRef<Target> for Target .

So now I would like to know: what was the compiler thinking? I still cannot associate the problem with the error message.

+5
source share
1 answer

You cannot avoid using input in standard From / Into traits.

They are defined to always consume input. Their definition defines both input and output as native types with unrelated lifetimes, so you can’t even "cheat" when trying to use a link.

  • If you return the link, you can instead implement AsRef<T> . Or, if your type is a thin shell / smart pointer, Deref<T> . You can provide as_foo() methods

  • If you return a new (native) object, the agreement is to provide to_foo() .

0
source

Source: https://habr.com/ru/post/1260042/


All Articles