But rustc says the input argument will drop at the end of the function, thus cannot run the destructor, so this function cannot be a constant function.
error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
--> src/lib.rs:6:21
|
6 | const fn convert<T>(option: Option<T>) -> MyOption<T> {
| ^^^^^^ the destructor for this type cannot be evaluated in constant functions
...
11 | }
| - value is dropped here
For more information about this error, try `rustc --explain E0493`.
Is there anybody who knows why the value dropped at the end of the function?
This error doesn't block my work as I don't actually need it to be a const fn, but I wonder why. Thanks.
Got it, thanks.
I found another interesting method to achieve this.
enum MyOption<T> {
Some(T),
None,
}
#[allow(dead_code)]
const fn convert<T>(mut option: Option<T>) -> MyOption<T> {
let converted = if option.is_some() {
// what does `take` and `unwrap` do?
MyOption::Some(option.take().unwrap())
} else {
MyOption::None
};
// `option` now is sure to be empty
std::mem::forget(option);
converted
}
But it works by using take().unwrap() which is a const operation, whose inner uses a special feature.
You don’t need to make use of take(), just unwrap():
const fn convert<T>(option: Option<T>) -> MyOption<T> {
if option.is_some() {
MyOption::Some(option.unwrap())
} else {
// We know the option is None, so this leaks nothing.
std::mem::forget(option);
MyOption::None
}
}
You could also write it in match form which I think might bring some clarity:
const fn convert<T>(option: Option<T>) -> MyOption<T> {
match option {
Some(_) => MyOption::Some(option.unwrap()),
None => {
// We know the option is None, so this leaks nothing.
std::mem::forget(option);
MyOption::None
}
}
}
The fundamental reason this works where a plain match doesn’t is that Option::unwrap() is allowed to use feature(const_precise_live_drops) internally. If that weren’t true, there would be no solution to the problem, because there would be no way to stop having the Option at all.