'AsRef'의 문제는 무엇입니까?
15084 단어 rustprogrammingbeginnersbites
AsRef
특성은 std lib의 모든 곳에 있으며 매우 편리합니다. 그러나 그것을 사용하는 이점은 너무 분명하지 않을 수 있습니다. 그러나 계속 읽으면 몇 가지 유용한 예와 적용할 위치를 볼 수 있습니다.실용적인 실제 프로젝트에서 떼어낸 아주 작은 녹 조각을 보여주는 시리즈"practical rust bites"의 두 번째 게시물입니다. 매우 실용적인 예를 통해 한 번에 하나의 Rust 관용구 또는 개념만 설명하는 것을 목표로 합니다.
배경
AsRef
는 found in the std::convert
모듈이 될 수 있으며 사용됩니다.저렴한 참조 대 참조 변환을 위해.
이것은 std 라이브러리에서 널리 사용되는 매우 필수적인 특성이며 한 유형에서 다른 유형으로 원활한 참조 변환을 돕습니다.
종종 그것은 작동 중이며 당신은 그것이 거기에 있다는 것을 깨닫지 못합니다.
예: 문자열 또는 &str
문자열을 매개변수로 받아들이고 싶었던 함수가 있었나요?
그런 다음 문자열 참조(
&str
에서와 같이) 또는 소유 문자열( String
에서와 같이)을 수락해야 하는지 스스로에게 질문했을 수도 있습니다.따라서 다음과 같은 것을 염두에 두어야 합니다.
fn take_a_str(some: &str) {}
그리고 다른 하나:
fn take_a_string(some: String) {}
So why not have both?!
바로 이 시점에서
AsRef<str>
가 매우 유용합니다.str
및 String
유형 모두 이 특성을 구현하기 때문입니다.fn take_a_str(some: impl AsRef<str>) {
let some = some.as_ref();
println!("{some}");
}
fn main() {
take_a_str("str");
take_a_str("String".to_string());
// also `&String` is supported:
let string_ref = "StringRef".to_string();
take_a_str(&string_ref);
}
check out the code on the playground
보시다시피
take_a_str
의 이 버전은 AsRef<str>
를 구현하는 유형을 허용합니다.그렇게 함으로써
some: impl AsRef<str>
제공된 유형에 대한 구체적인 가정을 하지 않습니다.대신 주어진 유형이 이 특성만 구현한다고 주장합니다.
예: 래퍼 유형
이 예제에서는 임의의 구조체에 대해 직접 구현
AsRef
할 수 있는 방법에 초점을 맞추고자 합니다.이 작은 프로그램을 살펴보겠습니다.
pub struct Envelope {
letter: String
}
fn main() {
let a_letter = Envelope {
letter: "a poem".to_string()
};
println!("this is a letter: {}", &a_letter);
}
그러나 물론 지금은 구현하지 않으며
Display
Rust 컴파일러도 동의한다고 말할 수 있습니다.error[E0277]: `Envelope` doesn't implement `std::fmt::Display`
--> src/main.rs:10:38
|
10 | println!("this is a letter: {}", &a_letter);
| ^^^^^^^^^ `Envelope` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Envelope`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
그러나 지금은
Display
를 무시하고 다른 사용 사례에 집중합니다. 즉 Envelope
의 내부 값에 액세스하려고 합니다.구현
AsRef<str>
으로 이 문제를 해결하려면 다음을 수행합니다.impl AsRef<str> for Envelope {
fn as_ref(&self) -> &str {
// here we up-call to the `AsRef<str>` implementation for String
self.letter.as_ref()
}
}
이것으로 우리는 약간의 조정이 필요합니다.
fn main() {
let a_letter = Envelope {
letter: "a poem".to_string()
};
println!("this is a letter: {}", a_letter.as_ref());
}
이제 Rust 컴파일러는 더 이상 불평하지 않습니다.
다시 말하지만, 물론 바로 이
Display
사례에 대해 println!
를 구현하는 것이 적절할 것입니다.check out the full example on the playground
예: 구성된 유형
나는 인정해야 합니다. 이 예를 약간의 소금으로 받아들입니다. 이런 용도일 가능성이 매우 높음
더 큰 구조체에 문제가 발생할 수 있습니다. 따라서 일반적으로 구조체에 2개 이상의 필드가 있는 경우 이 경로를 따르지 않는 것이 좋습니다.
가중치를 나타내는 간단한 구조체를 살펴보겠습니다.
struct Weight {
weight: f32,
unit: String
}
impl Weight {
/// Weight in Tons that is 157.47 stones
pub fn from_tons(weight: f32) -> Self {
Self { weight, unit: "t".to_string() }
}
/// Weight in Stones
pub fn from_stones(weight: f32) -> Self {
Self { weight, unit: "st".to_string() }
}
}
보시다시피 우리는
pub
필드와 getter 접근자 함수를 제공하지 않았습니다.So how we can actually get our hand on the data inside?
짐작하셨겠지만,
AsRef
는 여기서도 우리 친구입니다.impl AsRef<str> for Weight {
fn as_ref(&self) -> &str {
&self.unit
}
}
impl AsRef<f32> for Weight {
fn as_ref(&self) -> &f32 {
&self.weight
}
}
그래서 여기서 우리는
AsRef
및 f32
유형에 대해 str
특성을 사용하여 구조체 내부의 가중치 및 단위에 액세스합니다.fn main() {
let a_ton = Weight::from_tons(1.3);
let tons: &f32 = a_ton.as_ref();
let unit: &str = a_ton.as_ref();
println!("a weight of {tons} {unit}");
}
변수 바인딩을 건너뛰고 덜 장황하게 만들 수도 있습니다.
fn main() {
let a_ton = Weight::from_tons(1.3);
println!(
"a weight of {} {}",
a_ton.as_ref() as &f32,
a_ton.as_ref() as &str
);
}
checkout the full example on the playground
마무리
AsRef
는 매우 편리한 도구이며 표준 라이브러리를 살펴보면 많은 유형에 대해 구현된 것을 찾을 수 있습니다.이로 인해 많은 참조 유형이 상호 교환 가능해지고 전반적인 인체 공학이 크게 향상됩니다.
또한
AsRef
가 액세서리 메서드나 공용 필드를 제공하지 않고 구조체의 내부 데이터에 액세스하는 데 유용할 수 있는 방법을 살펴보았습니다.구조체의 내부 값을 가져오는 매우 관련된 함수이지만 값(참조가 아님)은 .into_inner() 입니다.
보시다시피 std lib에서 많이 사용되지만 특성에 구속되지는 않습니다. 따라서 이것은 관례에 가깝습니다. 구조체를 소비하고 내부 래핑된 유형을 펼쳐야 할 때마다
.into_inner()
가 공통 스키마입니다.이 게시물에 사용된 버전:
$ cargo --version && rustc --version
cargo 1.61.0 (a028ae42f 2022-04-29)
rustc 1.61.0 (fe5b13d68 2022-05-18)
새 블로그 게시물 및 기타 녹 관련 뉴스에 대한 업데이트를 받으려면 다음을 수행하십시오.
Reference
이 문제에 관하여('AsRef'의 문제는 무엇입니까?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/5422m4n/what-is-the-matter-with-asref-271p텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)