FromStr
FromStr
トレイトが実装されていると、 .parse()
が利用可能になる。
変換するだけなら TryFrom<&str>
か From<&str>
があれば十分なのだが、一応有用そうであれば実装しておくと良い。
#![allow(unused)] fn main() { // 追加の制約のない型の場合。 #[repr(transparent)] pub struct MyStr(str); #[derive(Clone)] pub struct MyString(String); impl From<&str> for MyString { fn from(s: &str) -> Self { unimplemented!() } } impl From<Box<str>> for Box<MyStr> { fn from(s: Box<str>) -> Self { unimplemented!() } } impl std::str::FromStr for MyString { type Err = std::convert::Infallible; #[inline] fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(s.into()) } } impl std::str::FromStr for Box<MyStr> { type Err = std::convert::Infallible; #[inline] fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Box::<str>::from(s).into()) } } }
失敗しない変換であれば From
で既に実装済のはずなので、そちらに丸投げすればよい。
失敗しない変換のエラー型としては std::convert::Infallible
を使う。
これは実行時に値を持てない型で、最適化に強力に貢献するはずである。
#![allow(unused)] fn main() { // 追加の制約付きの型の場合。 use std::convert::TryFrom; struct AsciiError; #[repr(transparent)] struct AsciiStr(str); struct AsciiString(String); impl TryFrom<&str> for AsciiString { type Error = AsciiError; fn try_from(s: &str) -> Result<Self, Self::Error> { unimplemented!() } } impl TryFrom<&str> for Box<AsciiStr> { type Error = AsciiError; fn try_from(s: &str) -> Result<Self, Self::Error> { unimplemented!() } } impl std::str::FromStr for AsciiString { type Err = AsciiError; #[inline] fn from_str(s: &str) -> Result<Self, Self::Err> { TryFrom::try_from(s) } } impl std::str::FromStr for Box<AsciiStr> { type Err = AsciiError; #[inline] fn from_str(s: &str) -> Result<Self, Self::Err> { TryFrom::try_from(s) } } }
失敗のおそれがあっても、 FromStr
は所有権なしの str
からの変換専用であるから、変換元の値を保存する必要はなく、 AsciiError
で事足りる。