매우 자주 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>
를 로 변환하고 싶습니다 Option<&str>
.
이것을 작성하는 idomatic 방법은 무엇입니까?
답변
Rust 1.40부터 표준 라이브러리는 다음 Option::as_deref
을 수행해야합니다.
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_deref().unwrap_or("default string");
}
답변
당신은 사용할 수 있습니다 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");
}
우선, as_ref()
암시에 대한 참조를 필요 opt
주는 &Option<String>
(때문에 as_ref()
얻어 &self
, 즉이 기준을 수신한다), 및 그것으로 변 Option<&String>
. 그런 다음을 사용 map
하여 Option<&str>
. 다음은 수행하는 작업입니다 &**x
. 맨 오른쪽 *
(먼저 평가됨)은 단순히를 역 참조하여 lvalue를 &String
제공합니다 String
. 그런 다음 가장 왼쪽은 *
실제로 Deref
특성을 호출합니다 .을 String
구현 Deref<Target=str>
하여 str
lvalue를 제공하기 때문 입니다. 마지막으로 &
는 str
lvalue 의 주소를 가져 와서 &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);
}
&**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);
}
또는 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);
}
또는 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);
}
둘 중 하나가 작동 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));
}
답변
더 좋은 방법은 이것을 일반적으로 구현하는 것입니다 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)
}
}
효과적으로 일반화 as_ref
합니다.
답변
나는 (내가 그것을 사용) 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));
답변
할 수있는 한 가지 방법이 있습니다. 당신이 있다는 사실을 숙지 가 원래 유지하기 위해 String
주변을, 그렇지 않으면 어떤이는 것, &str
로 조각을 할 수?
let opt = Some(String::from("test")); // kept around
let unwrapped: &str = match opt.as_ref() {
Some(s) => s, // deref coercion
None => "default",
};