1

Is it possible to pass a primitive type (such as i32) as a function argument. For example, I want to read the user input and store it in a vector of my choosing with a function

use std::io;
fn main()
{
get_vectorized_line(i32) ;  
}

fn get_vectorized_line(expected_type: type)->Vec<expected_type>{
    let mut line_content=String::new();
    io::stdin().read_line(&mut line_content).expect("Could not read line");
    let vectorized_line: Vec<expected_type> = line_content.trim().split(" ").
    map(|s| s.parse().expect("Could not parse")).collect();
    return vectorized_line;
}

responds with expected value, found builtin type i32 when the function is called.

I know it is possible to pass types as arguments in Python, (and not in standard C without using macros).

I believe I could be using generic functions to do what I want. But I wanted clarity on this topic

  • 3
    Rust [does not have reflection](https://stackoverflow.com/q/36416773/1233251). There isn't a type for values representing types in Rust. – E_net4 Apr 21 '20 at 21:05
  • Thanks for the comment. Do you have a suggestion on how I should go about this task? With generic functions? – Vikramaditya Gaonkar Apr 21 '20 at 21:27
  • 2
    This seem to be exactly [what generics are for](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=87670d19da4432cb8eae3d49b6e76f9e). Any reason not to use them? – mcarton Apr 21 '20 at 22:26
  • I was not very familiar with generic functions. Thanks for the example code – Vikramaditya Gaonkar Apr 26 '20 at 10:06

2 Answers2

4

If you really like the syntax of passing a type as an argument:

macro_rules! gvl {
    ($t:ty) => {{
        let mut content = String::new();
        std::io::stdin().read_line(&mut content).unwrap();
        content.trim().split(' ').map(
            |s| s.parse::<$t>().unwrap()
        ).collect::<Vec<$t>>()
    }}
}

And tah-dah:

let _ = gvl!(i32);

No external type annotations required!


Please don't actually do that

Use first class types with a special syntax that is (almost) what you want:

let _ = gvl::<i32>();
fn gvl<T: FromStr>() -> Vec<T> where <T as FromStr>::Err: Debug {
    let mut content=String::new();
    stdin().read_line(&mut content).unwrap();
    content.trim().split(' ').map(
        |s| s.parse().unwrap()
    ).collect()
}
Community
  • 1
  • 1
springworks00
  • 104
  • 15
  • Could you please explain why you recommend against using generic functions in your answer? – Vikramaditya Gaonkar Apr 26 '20 at 10:11
  • I _do_ recommend using generic functions (2nd example); I _do not_ recommend using macros. The generic function is more easily type/error checked and conveys your intention much more clearly than the macro solution. – springworks00 Apr 26 '20 at 16:48
1

You can use generics on return types. Here the generic T has to implement FromStr (because it is parsed from str) and must be displayable (for the eventual panic message).

use std::io;

fn get_vectorized_line<T: std::str::FromStr>()->Vec<T> where <T as std::str::FromStr>::Err: std::fmt::Debug {
    let mut line_content=String::new();
    io::stdin().read_line(&mut line_content).expect("Could not read line");
    line_content.trim().split(' ').map(|s| s.parse().unwrap()).collect()
}

fn main()
{
    let vectorized_line: Vec<i32> = get_vectorized_line() ;  
}
Mubelotix
  • 81
  • 4