Is there any real difference between FromStr
and TryFrom<&str>
?
From the definitions in the documentation, they look identical once you substitute &str
for T
in TryFrom
:
pub trait FromStr {
type Err;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
pub trait TryFrom<T> {
type Error;
fn try_from(value: T) -> Result<Self, Self::Error>;
}
Then there is parse:
FromStr’s from_str method is often used implicitly, through str’s parse method.
But if we look at its implementation, we see that it does not do anything beyond providing a slightly shorter way of calling from_str
:
pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
FromStr::from_str(self)
}
If you look at TryFrom's library implementations, then it is almost exclusively composed of numerical conversions, though there is also:
impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N] where
T: Copy,
type Error = TryFromSliceError
which is reminiscent of
impl FromStr for String {
type Err = core::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<String, Self::Err> {
Ok(String::from(s))
}
}
Converting the example implementation of FromStr from the docs to TryFrom is trivial.
There was a similar question on Reddit to which the best answer seems to be "just implement both".
Finally there is this similar question though it uses the wrong type and the Serde context is a distraction.
So:
- Is there any real difference between
FromStr
andTryFrom<&str>
? - What is current best practice regarding their use?
- Is there any plan for the future towards improving the situation?