TryFrom and TryInto
TryFrom and TryInto: Fallible Conversions
In the previous challenge, you learned about From and Into traits for infallible conversions. But what happens when a conversion might fail? For example, converting a large i64 to a u8 could overflow, or parsing a string into a number might fail if the string contains invalid characters.
Rust provides TryFrom and TryInto traits in the standard library for fallible conversions - conversions that might not succeed. These traits return a Result type, allowing you to handle conversion failures gracefully instead of panicking.
pub trait TryFrom<T>: Sized {
type Error;
fn try_from(value: T) -> Result<Self, Self::Error>;
}
pub trait TryInto<T>: Sized {
type Error;
fn try_into(self) -> Result<T, Self::Error>;
}Just like From and Into, implementing TryFrom automatically gives you TryInto for free (due to a blanket implementation in the standard library).
Your Task
Implement the following types and their TryFrom implementations:
1. PositiveNumber
A wrapper around i32 that only accepts positive numbers (greater than 0).
- Implement
TryFrom<i32>forPositiveNumber - Return
Err("number must be positive")if the value is 0 or negative - The inner value should be accessible via the
.0field
2. Percentage
A wrapper around u8 that only accepts values from 0 to 100 (inclusive).
- Implement
TryFrom<i32>forPercentage - Return
Err("percentage must be between 0 and 100")if out of range - The inner value should be accessible via the
.0field
3. NonEmptyString
A wrapper around String that ensures the string is not empty.
- Implement
TryFrom<String>forNonEmptyString - Implement
TryFrom<&str>forNonEmptyString - Return
Err("string cannot be empty")if the string is empty - The inner value should be accessible via the
.0field
4. EvenNumber
A wrapper around i32 that only accepts even numbers.
- Implement
TryFrom<i32>forEvenNumber - Return
Err("number must be even")if the number is odd - The inner value should be accessible via the
.0field
5. AsciiChar
A wrapper around char that only accepts ASCII characters.
- Implement
TryFrom<char>forAsciiChar - Implement
TryFrom<u8>forAsciiChar(convert byte to char, then validate) - Return
Err("character must be ASCII")if the character is not ASCII - The inner value should be accessible via the
.0field
Examples
use tryfrom_tryinto::*;
// PositiveNumber
let pos: Result<PositiveNumber, _> = 42.try_into();
assert!(pos.is_ok());
assert_eq!(pos.unwrap().0, 42);
let neg: Result<PositiveNumber, _> = (-5).try_into();
assert!(neg.is_err());
// Percentage
let valid = Percentage::try_from(75);
assert!(valid.is_ok());
let invalid = Percentage::try_from(150);
assert!(invalid.is_err());
// NonEmptyString
let s = NonEmptyString::try_from("hello");
assert!(s.is_ok());
let empty = NonEmptyString::try_from("");
assert!(empty.is_err());
// EvenNumber
let even = EvenNumber::try_from(4);
assert!(even.is_ok());
let odd = EvenNumber::try_from(3);
assert!(odd.is_err());
// AsciiChar
let ascii = AsciiChar::try_from('A');
assert!(ascii.is_ok());
let non_ascii = AsciiChar::try_from('');
assert!(non_ascii.is_err());Hints
Click here to reveal hints
- The
TryFromtrait requires an associatedErrortype. For simple cases,&'static strworks well. - Remember that implementing
TryFrom<T>for your type automatically providesTryInto<YourType>forT. - Use the
?operator or pattern matching to handle results elegantly. - For
AsciiChar::try_from(u8), you can convert au8to acharusingchar::from(byte)orbyte as char. - The
char::is_ascii()method checks if a character is ASCII. - Zero is neither positive nor negative, so
PositiveNumber::try_from(0)should fail. - Even numbers include negative even numbers and zero: -4, -2, 0, 2, 4, ...
Run to execute your code and see test results here.