Дуже часто я отримую значення Option<String>
з розрахунку, і я хотів би використати це значення або стандартне значення за замовчуванням.
Це було б тривіально з цілим числом:
let opt: Option<i32> = Some(3);
let value = opt.unwrap_or(0); // 0 being the default
Але за допомогою a String
та a &str
компілятор скаржиться на невідповідні типи:
let opt: Option<String> = Some("some value".to_owned());
let value = opt.unwrap_or("default string");
Точна помилка:
error[E0308]: mismatched types
--> src/main.rs:4:31
|
4 | let value = opt.unwrap_or("default string");
| ^^^^^^^^^^^^^^^^
| |
| expected struct `std::string::String`, found reference
| help: try using a conversion method: `"default string".to_string()`
|
= note: expected type `std::string::String`
found type `&'static str`
Одним із варіантів є перетворення фрагмента рядка у рядок, що належить, як запропоновано rustc:
let value = opt.unwrap_or("default string".to_string());
Але це спричиняє розподіл, що небажано, коли я хочу негайно перетворити результат назад на фрагмент рядка, як у цьому виклику до Regex::new()
:
let rx: Regex = Regex::new(&opt.unwrap_or("default string".to_string()));
Я б скоріше перетворив Option<String>
на an, Option<&str>
щоб уникнути такого розподілу.
Який ідоматичний спосіб це написати?
map
не працює. Я не розумію, що відбувається з першимOptions<String>
та копією, яка посилається на нього, у випадкуas_deref
варіанту коду. Ось мій робочий код за допомогоюas_deref
:let device_id = UsbDeviceIdentifier::VidPidSn { vid: device.vendor_id, pid: device.product_id, sn: device.serial_number.as_deref().unwrap_or("") };
і моя перша спробаlet device_id = UsbDeviceIdentifier::VidPidSn { vid: device.vendor_id, pid: device.product_id, sn: device.serial_number.map(|s| s.as_str()).unwrap_or("") };
.