3

Is there a more concise way to achieve the following?

fn boxed_option<T>(thing: Option<T>) -> Option<Box<T>> {
    match thing {
        Some(x) => Some(Box::new(x)),
        None => None,
    }
}
Timmmm
  • 88,195
  • 71
  • 364
  • 509

1 Answers1

12

Yes:

thing.map(Box::new)

I would strongly recommend memorizing all the methods on Iterator, Option and Result as they are so pervasively used in Rust. Option and Result have fewer than 25 inherent methods each, many of which have substantial overlap between the two types. At least read all of them to know what is available and memorize that. You can always open up the documentation again to find the exact name.


I actually can't quite get this to work.

fn function_2<F>(foo: Option<F>)
    where F: 'static + FnMut()
{
    let tmp: Option<Box<FnMut()>> = foo.map(Box::new);
}
error[E0308]: mismatched types
  --> src/main.rs:14:37
   |
14 |     let tmp: Option<Box<FnMut()>> = foo.map(Box::new);
   |                                     ^^^^^^^^^^^^^^^^^ expected trait std::ops::FnMut, found type parameter
   |
   = note: expected type `std::option::Option<Box<std::ops::FnMut()>>`
   = note:    found type `std::option::Option<Box<F>>`

The original code here wan't just transforming one type to another, it was also creating a trait object. I can't say for sure why that form of creating a trait object allowed to be implicit and this isn't:

foo.map(|f| Box::new(f));

However, you can instead say:

foo.map(|f| Box::new(f) as Box<FnMut()>);

(and no need to specify the type on the variable, of course).


Pedantically, "boxing an Option" would be Box<Option<T>>.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • "*all methods*" is quite a lot... maybe start with: `map()`, `map_err()` and `and_then()` as they are *probably* the most important ones and apply to many other types (apart from `Iterator`, `Option` and `Result`) as well. But I agree: getting familiar with most of the methods is important. – Lukas Kalbertodt Dec 17 '16 at 18:14
  • I actually can't quite get this to work. See [this code](https://play.rust-lang.org/?gist=0c2b17c5bc7c0a8507d3f60cd2043357&version=stable&backtrace=0). I found [this related question](https://stackoverflow.com/questions/29879372/expected-trait-coreopsfnmut-found-type-parameter) but still can't quite work it out. /noob – Timmmm Dec 17 '16 at 22:10
  • (Btw that code I linked doesn't use `map`, but it shows the same problem I have when I replace `match` in my actual code with `map`.) – Timmmm Dec 17 '16 at 22:11
  • @Timmmm that code has multiple errors, I've addressed one relevant here, the other (IMO more fundamental) issue is addressed by [Is there any way to return a reference to a variable created in a function?](http://stackoverflow.com/q/32682876/155423). – Shepmaster Dec 17 '16 at 22:43
  • Ah yeah I tried returning by value but it complained something wasn't `Sized`. Not returning references makes sense from a C++ point of view. I was imagining Rust had some kind of Go-like escape analysis thing for some reason. Thanks for the tons of help you're giving me by the way! – Timmmm Dec 17 '16 at 22:48