[rustlings] conversion problem

Hello,

I have this code :

// The From trait is used for value-to-value conversions.
// If From is implemented correctly for a type, the Into trait should work conversely.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
#[derive(Debug)]
struct Person {
    name: String,
    age: usize,
}

// We implement the Default trait to use it as a fallback
// when the provided string is not convertible into a Person object
impl Default for Person {
    fn default() -> Person {
        Person {
            name: String::from("John"),
            age: 30,
        }
    }
}

// Your task is to complete this implementation
// in order for the line `let p = Person::from("Mark,20")` to compile
// Please note that you'll need to parse the age component into a `usize`
// with something like `"4".parse::<usize>()`. The outcome of this needs to
// be handled appropriately.
//
// Steps:
// 1. If the length of the provided string is 0, then return the default of Person
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. If the name is empty, then return the default of Person
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return the default of Person
// Otherwise, then return an instantiated Person object with the results

// I AM NOT DONE

impl From<&str> for Person {
    fn from(s: &str) -> Person {
        if s.is_empty() {
            Default::default()
        }

        let splitted_name: Vec<&str> = s.split(',').collect();
        let parsed_name = &splitted_name[0];
        if parsed_name.is_empty() {
            Default::default()
        }

        let parsed_age = (&splitted_name[1]).parse::i32();

        Person{name: String::from("Roelof"), age:32}
     }
}

fn main() {
    // Use the `from` function
    let p1 = Person::from("Mark,20");
    // Since From is implemented for Person, we should be able to use Into
    let p2: Person = "Gerald,70".into();
    println!("{:?}", p1);
    println!("{:?}", p2);
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_default() {
        // Test that the default person is 30 year old John
        let dp = Person::default();
        assert_eq!(dp.name, "John");
        assert_eq!(dp.age, 30);
    }
    #[test]
    fn test_bad_convert() {
        // Test that John is returned when bad string is provided
        let p = Person::from("");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }
    #[test]
    fn test_good_convert() {
        // Test that "Mark,20" works
        let p = Person::from("Mark,20");
        assert_eq!(p.name, "Mark");
        assert_eq!(p.age, 20);
    }
    #[test]
    fn test_bad_age() {
        // Test that "Mark,twenty" will return the default person due to an error in parsing age
        let p = Person::from("Mark,twenty");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }

    #[test]
    fn test_missing_comma_and_age() {
        let p: Person = Person::from("Mark");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }

    #[test]
    fn test_missing_age() {
        let p: Person = Person::from("Mark,");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }

    #[test]
    fn test_missing_name() {
        let p: Person = Person::from(",1");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }

    #[test]
    fn test_missing_name_and_age() {
        let p: Person = Person::from(",");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }

    #[test]
    fn test_missing_name_and_invalid_age() {
        let p: Person = Person::from(",one");
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 30);
    }
}

but when I run the test I see this :

! Compiling of exercises/conversions/from_into.rs failed! Please try again. Here's the output:
error: expected one of `(`, `.`, `;`, `?`, or an operator, found `::`
  --> exercises/conversions/from_into.rs:50:51
   |
50 |         let parsed_age = (&splitted_name[1]).parse::i32();
   |                                                   ^^ expected one of `(`, `.`, `;`, `?`, or an operator

error: aborting due to previous error

The syntax you're trying to use is called the "turbofish" syntax. You need to specify the generic type in angle brackets. You want

let parsed_age = (&splitted_name[1]).parse::<i32>();

For more details, see this blog post

There's at least one more error (not a syntactic, but a semantic one) in the code you posted. These:

do nothing, they throw away the result of the Default::default() call and continue with the rest of the function, where it will panic at splitted_name[1] because that vector will have a single element, an empty string.

You seem to be confused about the distinction between control flow and block-like expressions yielding the last expression of their body. The if, match and block expression do NOT imply an automatic return. You still need an explicit return for early returning. It is only the case that the last (or only) expression of a function body will supply the return value of the function – this is only logical because there's nowhere for control flow to continue after the last expression. Preceding expressions do not have this property, they do not silently alter control flow.

1 Like