我经常Option<String>从计算中获得一个,我想使用这个值或默认的硬编码值.
这对于一个整数来说是微不足道的:
let opt: Option<i32> = Some(3);
let value = opt.unwrap_or(0); // 0 being the default
Run Code Online (Sandbox Code Playgroud)
但是使用a String和a &str,编译器会抱怨类型不匹配:
let opt: Option<String> = Some("some value".to_owned());
let value = opt.unwrap_or("default string");
Run Code Online (Sandbox Code Playgroud)
这里的确切错误是:
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`
Run Code Online (Sandbox Code Playgroud)
一种选择是将字符串切片转换为拥有的String,如rustc所示:
let value = opt.unwrap_or("default string".to_string());
Run Code Online (Sandbox Code Playgroud)
但这会导致分配,当我想立即将结果转换回字符串切片时,这是不合需要的,如此调用Regex::new():
let rx: Regex = Regex::new(&opt.unwrap_or("default string".to_string()));
Run Code Online (Sandbox Code Playgroud)
我宁愿将其转换Option<String>为a Option<&str>来避免这种分配.
写这个的人是什么?
Fra*_*gné 46
您可以使用as_ref()和map()转换Option<String>为Option<&str>.
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map(|x| &**x).unwrap_or("default string");
}
Run Code Online (Sandbox Code Playgroud)
首先,as_ref()隐式地接受引用opt,给出&Option<String>(因为as_ref()take &self,即它接收引用),并将其转换为Option<&String>.然后我们用map它来转换为Option<&str>.这是做什么的&**x:最右边*(首先评估)简单地取消引用&String,给出一个String左值.然后,最左边*实际调用Deref特征,因为String 实现 Deref<Target=str>,给我们一个str左值.最后,&获取str左值的地址,给我们一个&str.
您可以在此进一步通过简化位map_or结合map,并unwrap_or在一个单一的操作:
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", |x| &**x);
}
Run Code Online (Sandbox Code Playgroud)
如果&**x看起来太神奇了,你可以写String::as_str:
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", String::as_str);
}
Run Code Online (Sandbox Code Playgroud)
或String::as_ref(来自AsRef特质,在前奏中):
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", String::as_ref);
}
Run Code Online (Sandbox Code Playgroud)
或者String::deref(虽然你也需要导入Deref特征):
use std::ops::Deref;
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", String::deref);
}
Run Code Online (Sandbox Code Playgroud)
要使这些中的任何一个起作用,Option<String>只要需要保持可用Option<&str>或未包装的&str需要,您就需要保留所有者.如果这太复杂了,你可以使用Cow.
use std::borrow::Cow::{Borrowed, Owned};
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.map_or(Borrowed("default string"), |x| Owned(x));
}
Run Code Online (Sandbox Code Playgroud)
Vee*_*rac 19
一个更好的方法可能是实现这一点T: Deref:
use std::ops::Deref;
trait OptionDeref<T: Deref> {
fn as_deref(&self) -> Option<&T::Target>;
}
impl<T: Deref> OptionDeref<T> for Option<T> {
fn as_deref(&self) -> Option<&T::Target> {
self.as_ref().map(Deref::deref)
}
}
Run Code Online (Sandbox Code Playgroud)
这有效地概括了as_ref.
She*_*ter 15
标准库具有仅在夜间运行的不稳定函数Option::as_deref:
#![feature(inner_deref)]
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_deref().unwrap_or("default string");
}
Run Code Online (Sandbox Code Playgroud)
计划在Rust 1.40中稳定该功能。
尽管我喜欢 Veedrac 的答案(我使用过它),但如果您在某一时刻需要它并且您想要具有表现力的东西,您可以使用as_ref(),map和String::as_str链:
let opt: Option<String> = Some("some value".to_string());
assert_eq!(Some("some value"), opt.as_ref().map(String::as_str));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7801 次 |
| 最近记录: |