Hi! I'm coming to Rust from a JavaScript/Python background and trying to wrap my head around the type system and lifetimes.
I'm creating a daily task manager as my first little Rust project. I'm using json files to store my tasks/history for right now and I've been using separate functions to import each file. Now I'm trying to abstract this into one function and everything is falling apart.
This is the minimal version of what's been working:
use serde::{Deserialize, Serialize};
use serde_json::Result;
#[derive(Serialize, Deserialize, Clone, Debug)]
struct Task {
// stuff
}
#[derive(Serialize, Deserialize, Clone, Debug)]
struct WorkDay {
// more stuff
}
fn import_tasks() -> Vec<Task> {
let mut file = File::open("tasks.json")
.expect("Can't find tasks file");
let mut contents = String::new();
file.read_to_string(&mut contents);
let tasks: Vec<WorkDay> = serde_json::from_str(&contents)
.expect("serde error");
tasks
}
fn import_history() -> Vec<WorkDay> {
let mut file = File::open("history.json")
.expect("Can't find history file");
let mut contents = String::new();
file.read_to_string(&mut contents);
let history: Vec<WorkDay> = serde_json::from_str(&contents)
.expect("serde error");
history
}
fn main() {
let tasks = import_tasks();
let history = import_history();
}
Lots of repeated code that should be abstracted away. Ideally, I'd want to have a function that I could call like
let tasks: Vec<Task> = import_json_file("tasks.json");
let history: Vec<Workday> = import_json_file("history.json");
But everything I try makes the compiler angry! This is the best I've been able to do:
fn import_json_file<'a, T>(s: &'a str) -> Vec<T>
where
T: Deserialize<'a>
{
let mut file = File::open(s)
.expect("failed to find file");
let mut contents = String::new();
file.read_to_string(&mut contents);
let rv: Vec::<T> = serde_json::from_str(&contents)
.expect("Serde error")
.clone();
rv
}
But even with that, I get the following errors:
- type annotations needed: cannot infer type of the type parameter `T` declared on the function `from_str`
- consider specifying the generic argument: `::<T>`
I'm just completely lost at this point. Is it that I'm trying to wrap the the generic type in a vector? I have no idea. Any help would be very much appreciated.