I have an Option<&str> and I would like to end up with an Option<String>. For other types, Option::cloned would be an easy way to do that. The docs even say:
pub fn cloned(self) -> Option<T>
Maps an Option<&T> to an Option<T> by cloning the contents of the option.
However, trying this actually results in a compile error:
fn main() {
let unowned_str_maybe: Option<&str> = Some("abc");
let owned_str_maybe: Option<String> = unowned_str_maybe.cloned(); // <-- unsatisfied trait bounds
println!("{:?}", owned_str_maybe);
}
/* Compile error is:
error[E0599]: the method `cloned` exists for enum `Option<&str>`, but its trait bounds were not satisfied
--> src/main.rs:5:61
|
5 | let owned_str_maybe: Option<String> = unowned_str_maybe.cloned(); // <-- unsatisfied trait bounds
| ^^^^^^ method cannot be called on `Option<&str>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`str: Sized`
`str: Clone`
`Option<&str>: Iterator`
which is required by `&mut Option<&str>: Iterator`
*/
Using a more verbose (less idiomatic?) construction of .map(|x| x.to_string()) does compile. Why does Option::cloned not work for converting &str to String?
The reason is that Clone (which is used by Option::cloned) is used only to convert from &T to T, not from &T to U, even if semantically U is an owned version of &T (as String is to &str). In fact, you probably wouldn't expect this function to compile:
fn cloned(input: &str) -> String {
input.clone()
}
But Option::cloned is, essentially, .map(cloned), so it will work only if cloned works.
In fact, your approach with to_string is probably idiomatic. You probably could use function reference instead of closure, i.e. .map(ToString::to_string), or replace to_string with to_owned, but this is not so important.
Related
I have the following code that tries to take a reference to a trait object from a boxed trait:
trait T {}
struct S {}
impl T for S {}
fn main() {
let struct_box: Box<S> = Box::new(S {});
let struct_ref: &S = &struct_box;
let trait_box: Box<T> = Box::new(S {});
let trait_ref: &T = &trait_box;
}
The compiler returns the following error:
error[E0277]: the trait bound `std::boxed::Box<T>: T` is not satisfied
--> src/main.rs:12:25
|
12 | let trait_ref: &T = &trait_box;
| ^^^^^^^^^^ the trait `T` is not implemented for `std::boxed::Box<T>`
|
= note: required for the cast to the object type `T`
How do I properly borrow &T from Box<T>?
Box<T> implements the AsRef<T> trait, which provides the method as_ref(), so you can turn it into a reference that way:
let trait_ref: &T = trait_box.as_ref();
Normally, deref coercions mean that you don't usually need to write this out explicitly. If you pass a value of type Box<T> to a function that takes &T, the compiler will insert the conversion for you. If you want to call one of the methods on T that takes &self, the compiler will insert the conversion for you. However, deref coercion doesn't apply to a cast to a trait object type (the compiler will choose an unsizing coercion instead, which is what happens in your example).
Borrow the contents of the Box, rather than the Box itself:
let trait_ref: &T = &*trait_box;
The reason the line involving &S works is because the only way for Rust to get from Box<S> to &S is via "deref coercion"; that is, it repeatedly dereferences the value until either the types match, or it can't dereference any further.
Coercing to a trait object, on the other hand, isn't done using dereferencing at all; it involves constructing a new pointer directly from the given one. If it can't do that, it fails.
I have the following code that tries to take a reference to a trait object from a boxed trait:
trait T {}
struct S {}
impl T for S {}
fn main() {
let struct_box: Box<S> = Box::new(S {});
let struct_ref: &S = &struct_box;
let trait_box: Box<T> = Box::new(S {});
let trait_ref: &T = &trait_box;
}
The compiler returns the following error:
error[E0277]: the trait bound `std::boxed::Box<T>: T` is not satisfied
--> src/main.rs:12:25
|
12 | let trait_ref: &T = &trait_box;
| ^^^^^^^^^^ the trait `T` is not implemented for `std::boxed::Box<T>`
|
= note: required for the cast to the object type `T`
How do I properly borrow &T from Box<T>?
Box<T> implements the AsRef<T> trait, which provides the method as_ref(), so you can turn it into a reference that way:
let trait_ref: &T = trait_box.as_ref();
Normally, deref coercions mean that you don't usually need to write this out explicitly. If you pass a value of type Box<T> to a function that takes &T, the compiler will insert the conversion for you. If you want to call one of the methods on T that takes &self, the compiler will insert the conversion for you. However, deref coercion doesn't apply to a cast to a trait object type (the compiler will choose an unsizing coercion instead, which is what happens in your example).
Borrow the contents of the Box, rather than the Box itself:
let trait_ref: &T = &*trait_box;
The reason the line involving &S works is because the only way for Rust to get from Box<S> to &S is via "deref coercion"; that is, it repeatedly dereferences the value until either the types match, or it can't dereference any further.
Coercing to a trait object, on the other hand, isn't done using dereferencing at all; it involves constructing a new pointer directly from the given one. If it can't do that, it fails.
I'm trying to generalize .split from slices to iterators, and I can't seem to get the types right. This is partially because I'm not very experienced with Rust, and partially because the error message is weirdly vague for what I've seen from Rust. I've included what I believe are the relevant snippets, but there's also a trait Splittable and an implementation for it. The errors (I believe the second error is caused by the first, please tell me if that's not correct):
struct Split<I: Iterator, P: Fn(&I::Item) -> bool> {
iter: I,
pred: P,
}
impl<I: Iterator, P: Fn(&I::Item) -> bool> Iterator for Split<I, P> {
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.cloned()
.position(|x| (self.pred)(&x))
.map(|i| self.iter.take(i))
}
}
error[E0271]: type mismatch resolving `<I as std::iter::Iterator>::Item == &_`
--> src/main.rs:13:14
|
13 | .cloned()
| ^^^^^^ expected associated type, found reference
|
= note: expected associated type `<I as std::iter::Iterator>::Item`
found reference `&_`
= note: consider constraining the associated type `<I as std::iter::Iterator>::Item` to `&_` or calling a method that returns `<I as std::iter::Iterator>::Item`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0599]: no method named `position` found for struct `std::iter::Cloned<I>` in the current scope
--> src/main.rs:14:14
|
14 | .position(|x| (self.pred)(&x))
| ^^^^^^^^ method not found in `std::iter::Cloned<I>`
|
= note: the method `position` exists but the following trait bounds were not satisfied:
`<I as std::iter::Iterator>::Item = &_`
which is required by `std::iter::Cloned<I>: std::iter::Iterator`
The particular error message you are getting is a little misleading. What it is really complaining about is that std::slice::cloned requires an iterator over references, which you can see from its definition:
fn cloned<'a, T>(self) -> Cloned<Self>
where
Self: Iterator<Item = &'a T>,
T: 'a + Clone,
It requires an iterator over references to items that implement Clone (and the description states that it is useful for converting iterators over &T to iterators over T).
I suspect, however, that you are not trying to clone the items that are being iterated, rather that you are trying to clone the iterator itself. For that you would use the clone method, rather than cloned, and you would have to add a bound to ensure that the iterator is clonable, like this:
struct Split<I, P>
where
I: Iterator + Clone,
P: Fn(&I::Item) -> bool
There are a few other problems in your code:
You are borrowing self multiple times, to access the iter and pred.
You are effectively moving self.iter into the closure inside map
take consumes the iterator you call it on, so even if you refactor to avoid the above two problems, it still will not compile.
If you did intend to restrict your implementation to iterators over references, you could define your bounds like this:
struct Split<'a, I, T, P>
where
I: Iterator<Item=&'a T>,
T: 'a + Clone,
P: Fn(&I::Item) -> bool
Then you would be able to use cloned.
I have the following code that tries to take a reference to a trait object from a boxed trait:
trait T {}
struct S {}
impl T for S {}
fn main() {
let struct_box: Box<S> = Box::new(S {});
let struct_ref: &S = &struct_box;
let trait_box: Box<T> = Box::new(S {});
let trait_ref: &T = &trait_box;
}
The compiler returns the following error:
error[E0277]: the trait bound `std::boxed::Box<T>: T` is not satisfied
--> src/main.rs:12:25
|
12 | let trait_ref: &T = &trait_box;
| ^^^^^^^^^^ the trait `T` is not implemented for `std::boxed::Box<T>`
|
= note: required for the cast to the object type `T`
How do I properly borrow &T from Box<T>?
Box<T> implements the AsRef<T> trait, which provides the method as_ref(), so you can turn it into a reference that way:
let trait_ref: &T = trait_box.as_ref();
Normally, deref coercions mean that you don't usually need to write this out explicitly. If you pass a value of type Box<T> to a function that takes &T, the compiler will insert the conversion for you. If you want to call one of the methods on T that takes &self, the compiler will insert the conversion for you. However, deref coercion doesn't apply to a cast to a trait object type (the compiler will choose an unsizing coercion instead, which is what happens in your example).
Borrow the contents of the Box, rather than the Box itself:
let trait_ref: &T = &*trait_box;
The reason the line involving &S works is because the only way for Rust to get from Box<S> to &S is via "deref coercion"; that is, it repeatedly dereferences the value until either the types match, or it can't dereference any further.
Coercing to a trait object, on the other hand, isn't done using dereferencing at all; it involves constructing a new pointer directly from the given one. If it can't do that, it fails.
I tried to create vector of closures:
fn main() {
let mut vec = Vec::new();
vec.push(Box::new(|| 10));
vec.push(Box::new(|| 20));
println!("{}", vec[0]());
println!("{}", vec[1]());
}
That yielded the following error report:
error[E0308]: mismatched types
--> src/main.rs:5:23
|
5 | vec.push(Box::new(|| 20));
| ^^^^^ expected closure, found a different closure
|
= note: expected type `[closure#src/main.rs:4:23: 4:28]`
found type `[closure#src/main.rs:5:23: 5:28]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
I fixed it by specifying the type explicitly:
let mut vec: Vec<Box<Fn() -> i32>> = Vec::new();
What is the inferred type of vec and why is it that way?
Each closure has an auto-generated, unique, anonymous type. As soon as you add the first closure to the vector, that is the type of all items in the vector. However, when you try to add the second closure, it has a different auto-generated, unique, anonymous type, and so you get the error listed.
Closures are essentially structs that are created by the compiler that implement one of the Fn* traits. The struct contains fields for all the variables captured by the closure, so it by definition needs to be unique, as each closure will capture different numbers and types of variables.
Why can't it just infer Box<Fn() -> i32>?
"can't" is a tough question to answer. It's possible that the compiler could iterate through all the traits of every type that is used to see if some intersection caused the code to compile, but that feels a bit magical to me. You could try opening a feature request or discussing it on one of the forums to see if there is general acceptance of such an idea.
However, Rust does try to make things explicit, especially things that might involve performance. When you go from a concrete struct to a trait object, you are introducing indirection, which has the possibility of being slower.
Right now, the Fn* traits work the same as a user-constructed trait:
trait MyTrait {
fn hello(&self) {}
}
struct MyStruct1;
impl MyTrait for MyStruct1 {}
struct MyStruct2;
impl MyTrait for MyStruct2 {}
fn main() {
let mut things = vec![];
things.push(MyStruct1);
things.push(MyStruct2);
}
error[E0308]: mismatched types
--> src/main.rs:14:17
|
14 | things.push(MyStruct2);
| ^^^^^^^^^ expected struct `MyStruct1`, found struct `MyStruct2`
|
= note: expected type `MyStruct1`
found type `MyStruct2`