Calling a function which takes a closure twice with different closures - rust

As a project for learning rust, I am writing a program which can parse sgf files (a format for storing go games, and technically also other games). Currently the program is supposed to parse strings of the type (this is just an exampel) ";B[ab]B[cd]W[ef]B[gh]" into [Black((0,1)),Black((2,3,)),White((4,5)),Black((6,7))]
For this I am using the parser-combinators library.
I have run into the following error:
main.rs:44:15: 44:39 error: can't infer the "kind" of the closure; explicitly annotate it; e.g. `|&:| {}` [E0187]
main.rs:44 pmove().map(|m| {Property::White(m)})
^~~~~~~~~~~~~~~~~~~~~~~~
main.rs:44:15: 44:39 error: mismatched types:
expected `closure[main.rs:39:15: 39:39]`,
found `closure[main.rs:44:15: 44:39]`
(expected closure,
found a different closure) [E0308]
main.rs:44 pmove().map(|m| {Property::White(m)})
^~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
Could not compile `go`.
The function in question is below. I am completely new to rust, so I can't really isolate the problem further or recreate it in a context without the parser-combinators library (might even have something to do with that library?).
fn parse_go_sgf(input: &str) -> Vec<Property> {
let alphabetic = |&:| {parser::satisfy(|c| {c.is_alphabetic()})};
let prop_value = |&: ident, value_type| {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(|c| c == '['),
parser::satisfy(|c| c == ']'),
value_type
)
)
};
let pmove = |&:| {
alphabetic().and(alphabetic())
.map(|a| {to_coord(a.0, a.1)})
};
let pblack = prop_value(
parser::string("B"),
pmove().map(|m| {Property::Black(m)}) //This is where I am first calling the map function.
);
let pwhite = prop_value(
parser::string("W"),
pmove().map(|m| {Property::White(m)}) //This is where the compiler complains
);
let pproperty = parser::try(pblack).or(pwhite);
let mut pnode = parser::spaces()
.with(parser::string(";"))
.with(parser::many(pproperty));
match pnode.parse(input) {
Ok((value, _)) => value,
Err(err) => {
println!("{}",err);
vec!(Property::Unkown)
}
}
}
So I am guessing this has something to do with closures all having different types. But in other cases it seems possible to call the same function with different closures. For example
let greater_than_forty_two = range(0, 100)
.find(|x| *x > 42);
let greater_than_forty_three = range(0, 100)
.find(|x| *x > 43);
Seems to work just fine.
So what is going on in my case that is different.
Also, as I am just learning, any general comments on the code are also welcome.

Unfortunately, you stumbled upon one of the rough edges in the Rust type system (which is, given the closure-heavy nature of parser-combinators, not really unexpected).
Here is a simplified example of your problem:
fn main() {
fn call_closure_fun<F: Fn(usize)>(f: F) { f(12) } // 1
fn print_int(prefix: &str, i: usize) { println!("{}: {}", prefix, i) }
let call_closure = |&: closure| call_closure_fun(closure); // 2
call_closure(|&: i| print_int("first", i)); // 3.1
call_closure(|&: i| print_int("second", i)); // 3.2
}
It gives exactly the same error as your code:
test.rs:8:18: 8:47 error: mismatched types:
expected `closure[test.rs:7:18: 7:46]`,
found `closure[test.rs:8:18: 8:47]`
(expected closure,
found a different closure) [E0308]
test.rs:8 call_closure(|&: i| print_int("second", i));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have (referenced in the comments in the code):
a function which accepts a closure of some concrete form;
a closure which calls a function (1) with its own argument;
two invocations of closure (1), passing different closures each time.
Rust closures are unboxed. It means that for each closure the compiler generates a fresh type which implements one of closure traits (Fn, FnMut, FnOnce). These types are anonymous - they don't have a name you can write out. All you know is that these types implement a certain trait.
Rust is a strongly- and statically-typed language: the compiler must know exact type of each variable and each parameter at the compile time. Consequently it has to assign types for every parameter of every closure you write. But what type should closure argument of (2) have? Ideally, it should be some generic type, just like in (1): the closure should accept any type as long as it implements a trait. However, Rust closures can't be generic, and so there is no syntax to specify that. So Rust compiler does the most natural thing it can - it infers the type of closure argument based on the first use of call_closure, i.e. from 3.1 invocation - that is, it assigns the anonymous type of the closure in 3.1!
But this anonymous type is different from the anonymous type of the closure in 3.2: the only thing they have in common is that they both implement Fn(usize). And this is exactly what error is about.
The best solution would be to use functions instead of closures because functions can be generic. Unfortunately, you won't be able to do that either: your closures return structures which contain closures inside themselves, something like
pub struct Satisfy<I, Pred> { ... }
where Pred is later constrained to be Pred: FnMut(char) -> bool. Again, because closures have anonymous types, you can't specify them in type signatures, so you won't be able to write out the signature of such generic function.
In fact, the following does work (because I've extracted closures for parser::satisfy() calls to parameters):
fn prop_value<'r, I, P, L, R>(ident: I, value_type: P, l: L, r: R) -> pp::With<pp::With<pp::With<pp::Spaces<&'r str>, I>, pp::Spaces<&'r str>>, pp::Between<pp::Satisfy<&'r str, L>, pp::Satisfy<&'r str, R>, P>>
where I: Parser<Input=&'r str, Output=&'r str>,
P: Parser<Input=&'r str, Output=Property>,
L: Fn(char) -> bool,
R: Fn(char) -> bool {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(l),
parser::satisfy(r),
value_type
)
)
}
And you'd use it like this:
let pblack = prop_value(
parser::string("B"),
pmove().map(|&: m| Property::Black(m)),
|c| c == '[', |c| c == ']'
);
let pwhite = prop_value(
parser::string("W"),
pmove().map(|&: m| Property::White(m)),
|c| c == '[', |c| c == ']'
);
pp is introduced with use parser::parser as pp.
This does work, but it is really ugly - I had to use the compiler error output to actually determine the required return type. With the slightest change in the function it will have to be adjusted again. Ideally this is solved with unboxed abstract return types - there is a postponed RFC on them - but we're still not there yet.

As the author of parser-combinators I will just chime in on another way of solving this, without needing to use the compiler to generate the return type.
As each parser is basically just a function together with 2 associated types there are implementations for the Parser trait for all function types.
impl <I, O> Parser for fn (State<I>) -> ParseResult<O, I>
where I: Stream { ... }
pub struct FnParser<I, O, F>(F);
impl <I, O, F> Parser for FnParser<I, O, F>
where I: Stream, F: FnMut(State<I>) -> ParseResult<O, I> { ... }
These should all be replaced by a single trait and the FnParser type removed, once the orphan checking allows it. In the meantime we can use the FnParser type to create a parser from a closure.
Using these traits we can essentially hide the big parser type returned from in Vladimir Matveev's example.
fn prop_value<'r, I, P, L, R>(ident: I, value_type: P, l: L, r: R, input: State<&'r str>) -> ParseResult<Property, &'r str>
where I: Parser<Input=&'r str, Output=&'r str>,
P: Parser<Input=&'r str, Output=Property>,
L: Fn(char) -> bool,
R: Fn(char) -> bool {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(l),
parser::satisfy(r),
value_type
)
).parse_state(input)
}
And we can now construct the parser with this
let parser = FnParser(move |input| prop_value(ident, value_type, l, r, input));
And this is basically the best we can do at the moment using rust. Unboxed anonymous return types would make all of this significantly easier since complex return types would not be needed (nor created since the library itself could be written to utilize this, avoiding the complex types entirely).

Two facets of Rust's closures are causing your problem, one, closures cannot be generic, and two, each closure is its own type. Because closure's cannot be generic,prop_value's parameter value_type must be a specific type. Because each closure is a specific type, the closure you pass to prop_value in pwhite is a different type from the one in pblack. What the compiler does is conclude that the value_type must have the type of the closure in pblack, and when it gets to pwhite it finds a different closure, and gives an error.
Judging from your code sample, the simplest solution would probably be to make prop_value a generic fn - it doesn't look like it needs to be a closure. Alternatively, you could declare its parameter value_type to be a closure trait object, e.g. &Fn(...) -> .... Here is a simplifed example demonstrating these approaches:
fn higher_fn<F: Fn() -> bool>(f: &F) -> bool {
f()
}
let higher_closure = |&: f: &Fn() -> bool | { f() };
let closure1 = |&:| { true };
let closure2 = |&:| { false };
higher_fn(&closure1);
higher_fn(&closure2);
higher_closure(&closure1);
higher_closure(&closure2);

The existing answer(s) are good, but I wanted to share an even smaller example of the problem:
fn thing<F: FnOnce(T), T>(f: F) {}
fn main() {
let caller = |&: f| {thing(f)};
caller(|&: _| {});
caller(|&: _| {});
}
When we define caller, its signature is not fully fixed yet. When we call it the first time, type inference sets the input and output types. In this example, after the first call, caller will be required to take a closure with a specific type, the type of the first closure. This is because each and every closure has its own unique, anonymous type. When we call caller a second time, the second closure's (unique, anonymous) type doesn't fit!
As #wingedsubmariner points out, there's no way to create closures with generic types. If we had hypothetical syntax like for<F: Fn()> |f: F| { ... }, then perhaps we could work around this. The suggestion to make a generic function is a good one.

Related

From and Into with binary std::ops: cannot infer type for type parameter `T`?

When I do
seq += u64::from(rhs);
Everything works. But I'd prefer the syntax of rhs.into() with that I'm currently getting,
error[E0283]: type annotations needed
--> src/sequence.rs:50:5
|
19 | seq += rhs.into();
| ^^ ---------- this method call resolves to `T`
| |
| cannot infer type for type parameter `T`
|
= note: cannot satisfy `_: Into<u64>`
= note: required because of the requirements on the impl of `AddAssign<_>` for `Sequence`
This .into() syntax normally works. Why doesn't type inference work on binary operators += such that if the LHS only implements AddAssign<u64> the RHS will coerce? And moreover, aside from using from what is the syntax (if possible) to provide this type information to .into that the compiler needs? I've tried things like .into::<u64>(rhs) and that also doesn't work.
I am implementing AddAssign like this,
impl<T: Into<u64>> AddAssign<T> for Sequence {
fn add_assign(&mut self, rhs: T) {...}
}
And From like this,
impl From<Sequence> for u64 {
fn from(seq: Sequence)-> u64 { ... }
}
You have a double Into indirection, probably by mistake. Since your type already implements AddAssign<T> where T: Into<u64>, then there is no need to add .into() to your right-hand member. It should be expected that the implementation of add_assign (not provided in your example) would call into underneath.
seq += rhs;
In fact, adding it would only bring ambiguity, because then the compiler was being told to call Into<X>::into(rhs) on a type X which is never mentioned nor constrained anywhere. The only constraint would be Into<u64>, but multiple types fulfill it.
A complete example:
use std::ops::AddAssign;
struct Sequence;
impl<T: Into<u64>> AddAssign<T> for Sequence {
fn add_assign(&mut self, rhs: T) {
let value: u64 = rhs.into();
// use value
}
}
fn main() {
let mut x = Sequence;
x += 6_u32;
}
what is the syntax (if possible) to provide this type information to .into that the compiler needs?
Again, this is not needed. But that would be possible with the so-called fully qualified syntax.
See also:
Why can't Rust infer the resulting type of Iterator::sum?

How can I add onto the end of a large [u8] variable in rust? [duplicate]

The following compiles:
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
let mut result = (0..list.len() - 1)
.map(|i| format!("For want of a {} the {} was lost.", list[i], list[i + 1]))
.collect::<Vec<String>>();
result.push(format!("And all for the want of a {}.", list[0]));
result.join("\n")
}
The following does not (see Playground):
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
let mut result = (0..list.len() - 1)
.map(|i| format!("For want of a {} the {} was lost.", list[i], list[i + 1]))
.collect::<Vec<String>>()
.push(format!("And all for the want of a {}.", list[0]))
.join("\n");
result
}
The compiler tells me
error[E0599]: no method named `join` found for type `()` in the current scope
--> src/lib.rs:9:10
|
9 | .join("\n");
| ^^^^
I get the same type of error if I try to compose just with push.
What I would expect is that collect returns B, aka Vec<String>. Vec is not (), and Vec of course has the methods I want to include in the list of composed functions.
Why can't I compose these functions? The explanation might include describing the "magic" of terminating the expression after collect() to get the compiler to instantiate the Vec in a way that does not happen when I compose with push etc.
If you read the documentation for Vec::push and look at the signature of the method, you will learn that it does not return the Vec:
pub fn push(&mut self, value: T)
Since there is no explicit return type, the return type is the unit type (). There is no method called join on (). You will need to write your code in multiple lines.
See also:
What is the purpose of the unit type in Rust?
I'd write this more functionally:
use itertools::Itertools; // 0.8.0
pub fn build_proverb(list: &[&str]) -> String {
let last = list
.get(0)
.map(|d| format!("And all for the want of a {}.", d));
list.windows(2)
.map(|d| format!("For want of a {} the {} was lost.", d[0], d[1]))
.chain(last)
.join("\n")
}
fn main() {
println!("{}", build_proverb(&["nail", "shoe"]));
}
See also:
What's an idiomatic way to print an iterator separated by spaces in Rust?
Thank you to everyone for the useful interactions. Everything stated in the previous response is precisely correct. And, there is a bigger picture as I'm learning Rust.
Coming from Haskell (with C training years ago), I bumped into the OO method chaining approach that uses a pointer to chain between method calls; no need for pure functions (i.e., what I was doing with let mut result = ..., which was then used/required to change the value of the Vec using push in result.push(...)). What I believe is a more general observation is that, in OO, it is "aok" to return unit because method chaining does not require a return value.
The custom code below defines push as a trait; it uses the same inputs as the "OO" push, but returns the updated self. Perhaps only as a side comment, this makes the function pure (output depends on input) but in practice, means the push defined as a trait enables the FP composition of functions I had come to expect was a norm (fair enough I thought at first given how much Rust borrows from Haskell).
What I was trying to accomplish, and at the heart of the question, is captured by the code solution that #Stargateur, #E_net4 and #Shepmaster put forward. With only the smallest edits is as follows:
(see playground)
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
list.windows(2)
.map(|d| format!("For want of a {} the {} was lost.", d[0], d[1]))
.collect::<Vec<_>>()
.push(format!("And all for the want of a {}.", list[0]))
.join("\n")
}
The solution requires that I define push as a trait that return the self,
type Vec in this instance.
trait MyPush<T> {
fn push(self, x: T) -> Vec<T>;
}
impl<T> MyPush<T> for Vec<T> {
fn push(mut self, x: T) -> Vec<T> {
Vec::push(&mut self, x);
self
}
}
Final observation, in surveying many of the Rust traits, I could not find a trait function that returns () (modulo e.g., Write that returns Result ()).
This contrasts with what I learned here to expect with struct and enum methods. Both traits and the OO methods have access to self and thus have each been described as "methods", but there seems to be an inherent difference worth noting: OO methods use a reference to enable sequentially changing self, FP traits (if you will) uses function composition that relies on the use of "pure", state-changing functions to accomplish the same (:: (self, newValue) -> self).
Perhaps as an aside, where Haskell achieves referential transparency in this situation by creating a new copy (modulo behind the scenes optimizations), Rust seems to accomplish something similar in the custom trait code by managing ownership (transferred to the trait function, and handed back by returning self).
A final piece to the "composing functions" puzzle: For composition to work, the output of one function needs to have the type required for the input of the next function. join worked both when I was passing it a value, and when I was passing it a reference (true with types that implement IntoIterator). So join seems to have the capacity to work in both the method chaining and function composition styles of programming.
Is this distinction between OO methods that don't rely on a return value and traits generally true in Rust? It seems to be the case "here and there". Case in point, in contrast to push where the line is clear, join seems to be on its way to being part of the standard library defined as both a method for SliceConcatExt and a trait function for SliceConcatExt (see rust src and the rust-lang issue discussion). The next question, would unifying the approaches in the standard library be consistent with the Rust design philosophy? (pay only for what you use, safe, performant, expressive and a joy to use)

Why does the compiler prevent me from using push on a Vec created using collect()?

The following compiles:
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
let mut result = (0..list.len() - 1)
.map(|i| format!("For want of a {} the {} was lost.", list[i], list[i + 1]))
.collect::<Vec<String>>();
result.push(format!("And all for the want of a {}.", list[0]));
result.join("\n")
}
The following does not (see Playground):
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
let mut result = (0..list.len() - 1)
.map(|i| format!("For want of a {} the {} was lost.", list[i], list[i + 1]))
.collect::<Vec<String>>()
.push(format!("And all for the want of a {}.", list[0]))
.join("\n");
result
}
The compiler tells me
error[E0599]: no method named `join` found for type `()` in the current scope
--> src/lib.rs:9:10
|
9 | .join("\n");
| ^^^^
I get the same type of error if I try to compose just with push.
What I would expect is that collect returns B, aka Vec<String>. Vec is not (), and Vec of course has the methods I want to include in the list of composed functions.
Why can't I compose these functions? The explanation might include describing the "magic" of terminating the expression after collect() to get the compiler to instantiate the Vec in a way that does not happen when I compose with push etc.
If you read the documentation for Vec::push and look at the signature of the method, you will learn that it does not return the Vec:
pub fn push(&mut self, value: T)
Since there is no explicit return type, the return type is the unit type (). There is no method called join on (). You will need to write your code in multiple lines.
See also:
What is the purpose of the unit type in Rust?
I'd write this more functionally:
use itertools::Itertools; // 0.8.0
pub fn build_proverb(list: &[&str]) -> String {
let last = list
.get(0)
.map(|d| format!("And all for the want of a {}.", d));
list.windows(2)
.map(|d| format!("For want of a {} the {} was lost.", d[0], d[1]))
.chain(last)
.join("\n")
}
fn main() {
println!("{}", build_proverb(&["nail", "shoe"]));
}
See also:
What's an idiomatic way to print an iterator separated by spaces in Rust?
Thank you to everyone for the useful interactions. Everything stated in the previous response is precisely correct. And, there is a bigger picture as I'm learning Rust.
Coming from Haskell (with C training years ago), I bumped into the OO method chaining approach that uses a pointer to chain between method calls; no need for pure functions (i.e., what I was doing with let mut result = ..., which was then used/required to change the value of the Vec using push in result.push(...)). What I believe is a more general observation is that, in OO, it is "aok" to return unit because method chaining does not require a return value.
The custom code below defines push as a trait; it uses the same inputs as the "OO" push, but returns the updated self. Perhaps only as a side comment, this makes the function pure (output depends on input) but in practice, means the push defined as a trait enables the FP composition of functions I had come to expect was a norm (fair enough I thought at first given how much Rust borrows from Haskell).
What I was trying to accomplish, and at the heart of the question, is captured by the code solution that #Stargateur, #E_net4 and #Shepmaster put forward. With only the smallest edits is as follows:
(see playground)
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
list.windows(2)
.map(|d| format!("For want of a {} the {} was lost.", d[0], d[1]))
.collect::<Vec<_>>()
.push(format!("And all for the want of a {}.", list[0]))
.join("\n")
}
The solution requires that I define push as a trait that return the self,
type Vec in this instance.
trait MyPush<T> {
fn push(self, x: T) -> Vec<T>;
}
impl<T> MyPush<T> for Vec<T> {
fn push(mut self, x: T) -> Vec<T> {
Vec::push(&mut self, x);
self
}
}
Final observation, in surveying many of the Rust traits, I could not find a trait function that returns () (modulo e.g., Write that returns Result ()).
This contrasts with what I learned here to expect with struct and enum methods. Both traits and the OO methods have access to self and thus have each been described as "methods", but there seems to be an inherent difference worth noting: OO methods use a reference to enable sequentially changing self, FP traits (if you will) uses function composition that relies on the use of "pure", state-changing functions to accomplish the same (:: (self, newValue) -> self).
Perhaps as an aside, where Haskell achieves referential transparency in this situation by creating a new copy (modulo behind the scenes optimizations), Rust seems to accomplish something similar in the custom trait code by managing ownership (transferred to the trait function, and handed back by returning self).
A final piece to the "composing functions" puzzle: For composition to work, the output of one function needs to have the type required for the input of the next function. join worked both when I was passing it a value, and when I was passing it a reference (true with types that implement IntoIterator). So join seems to have the capacity to work in both the method chaining and function composition styles of programming.
Is this distinction between OO methods that don't rely on a return value and traits generally true in Rust? It seems to be the case "here and there". Case in point, in contrast to push where the line is clear, join seems to be on its way to being part of the standard library defined as both a method for SliceConcatExt and a trait function for SliceConcatExt (see rust src and the rust-lang issue discussion). The next question, would unifying the approaches in the standard library be consistent with the Rust design philosophy? (pay only for what you use, safe, performant, expressive and a joy to use)

Is it possible to make my own Box-like wrapper?

I noticed that Box<T> implements everything that T implements and can be used transparently. For Example:
let mut x: Box<Vec<u8>> = Box::new(Vec::new());
x.push(5);
I would like to be able to do the same.
This is one use case:
Imagine I'm writing functions that operate using an axis X and an axis Y. I'm using values to change those axis that are of type numbers but belongs only to one or the other axis.
I would like my compiler to fail if I attempt to do operations with values that doesn't belong to the good axis.
Example:
let x = AxisX(5);
let y = AxisY(3);
let result = x + y; // error: incompatible types
I can do this by making a struct that will wrap the numbers:
struct AxisX(i32);
struct AxisY(i32);
But that won't give me access to all the methods that i32 provides like abs(). Example:
x.abs() + 3 // error: abs() does not exist
// ...maybe another error because I don't implement the addition...
Another possible use case:
You can appropriate yourself a struct of another library and implement or derive anything more you would want. For example: a struct that doesn't derive Debug could be wrapped and add the implementation for Debug.
You are looking for std::ops::Deref:
In addition to being used for explicit dereferencing operations with the (unary) * operator in immutable contexts, Deref is also used implicitly by the compiler in many circumstances. This mechanism is called 'Deref coercion'. In mutable contexts, DerefMut is used.
Further:
If T implements Deref<Target = U>, and x is a value of type T, then:
In immutable contexts, *x on non-pointer types is equivalent to *Deref::deref(&x).
Values of type &T are coerced to values of type &U
T implicitly implements all the (immutable) methods of the type U.
For more details, visit the chapter in The Rust Programming Language as well as the reference sections on the dereference operator, method resolution and type coercions.
By implementing Deref it will work:
impl Deref for AxisX {
type Target = i32;
fn deref(&self) -> &i32 {
&self.0
}
}
x.abs() + 3
You can see this in action on the Playground.
However, if you call functions from your underlying type (i32 in this case), the return type will remain the underlying type. Therefore
assert_eq!(AxisX(10).abs() + AxisY(20).abs(), 30);
will pass. To solve this, you may overwrite some of those methods you need:
impl AxisX {
pub fn abs(&self) -> Self {
// *self gets you `AxisX`
// **self dereferences to i32
AxisX((**self).abs())
}
}
With this, the above code fails. Take a look at it in action.

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

I have managed to make the Rust type checker go into an infinite loop. A very similar program compiles with no trouble. Why does the program I want not compile?
To save your time and effort, I have made minimal versions of the two programs that isolate the problem. Of course, the minimal version is a pointless program. You'll have to use your imagination to see my motivation.
Success
Let me start with the version that works. The struct F<T> wraps a T. The type Target can be converted from an F<T> provided 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 caller:
fn main() {
let x = Target;
let y = F(F(F(x)));
let z = Target::from(y);
println!("{:?}", z);
}
This runs and prints "Target".
Failure
The function f does not consume its argument. I would prefer it if the From conversion also did not consume its argument, because the type F<T> could be expensive or impossible to clone. I can write a custom trait FromRef that differs from std::convert::From by accepting an immutable borrow instead of an owned 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 ask my question more clearly, without messing around with lifetime parameters. (The behaviour of the type-checker is the same using From<&'a T>).
Here's 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)
}
}
This compiles. However, the main() function doesn't:
fn main() {
let x = Target;
let y = F(F(F(x)));
let z = Target::from_ref(y);
println!("{:?}", z);
}
It gives a huge error message beginning:
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've randomly fixed it!
The problem was that I forgot to implement FromRef<Target> for Target.
So I would now like to know: what was the compiler thinking? I still can't relate the problem to the error message.
You can't avoid consuming the input in the standard From/Into traits.
They are defined to always consume the input. Their definition specifies both input and output as owned types, with unrelated lifetimes, so you can't even "cheat" by trying to consume a reference.
If you're returning a reference, you can implement AsRef<T> instead. Or if your type is a thin wrapper/smart pointer, Deref<T>. You can provide methods as_foo()
If you're returning a new (owned) object, the convention is to provide to_foo() methods.

Resources