I want to be able to add two methods to the struct, with the same name, where they would return different data types.
struct NumParser<'a> {
splitting: Split<'a, &'a str>,
}
impl NumParser<'_> {
fn new<'a>(string: &'a str) -> NumParser<'a> {
NumParser{
splitting: string.trim().split(" "),
}
}
fn next(&mut self) -> u32 {
self.splitting.next().unwrap().parse().unwrap()
}
fn next(&mut self) -> u8 {
self.splitting.next().unwrap().parse().unwrap()
}
}
The returned type would be decided by the annotation or by the type of the variable that I'm assigning it to.
let mut parser: NumParser = NumParser::new(String::from("1 2 3 4 5"));
let var1: u32 = parser.next(); // the first next() would be called
let var2: u8 = parser.next(); // the second next() would be called
let arr: [u8; 2] = [parser.next(), parser.next()]; // both times the second next() would be called
var1 = parser.next(); // the first next() would be called, even without annotation
I tried using traits, but I can't seem to implement two functions with the same name that way as well.
Despite 2 upvoted answers to the contrary, you can define a method with a return type of either u8
or u32
(or really any number of and types you'd like) the only caveat is that you can't implement the methods as inherent methods of NumParser
but that you have to create a trait for them for example like this:
trait Next<T> {
fn next(&mut self) -> T;
}
Then you can define the 2 methods differing only in their return type as 2 distinct implementations of the trait for your struct:
impl Next<u32> for NumParser<'_> {
fn next(&mut self) -> u32 {
self.splitting.next().unwrap().parse().unwrap()
}
}
impl Next<u8> for NumParser<'_> {
fn next(&mut self) -> u8 {
self.splitting.next().unwrap().parse().unwrap()
}
}
Or if you wish to implement it for every T
that is parsable (that implements FromStr
):
impl<T: std::str::FromStr> Next<T> for NumParser<'_>
where
T::Err: Debug,
{
fn next(&mut self) -> T {
self.splitting.next().unwrap().parse().unwrap()
}
}
and the Rust compiler will choose the method to call depending on the type you need:
fn main() {
let s = "12 34 56 78";
let mut p = NumParser::new(s);
let a: u8 = p.next();
let b: u32 = p.next();
dbg!(a, b);
}