Sorry if the title is a bit vague, but I wouldn't know how to phrase it precisely. Also, this question might have been discussed already, but once again I don't know what to search for exactly, so I couldn't find anything related. So, the following code compiles:
use std::fs::File;
use std::io::{self,Read,BufReader,Error,ErrorKind};
// IO
trait ReadNumeric<T> {
fn read_numeric(&mut self) -> io::Result<T>;
}
// Specialized for i32
impl<R: Read> ReadNumeric<usize> for BufReader<R> {
fn read_numeric(&mut self) -> io::Result<usize> {
let mut buf = [0; 4];
self.read_exact(&mut buf)?;
let x = usize::try_from(u32::from_ne_bytes(buf));
x.map_err(|e| Error::new(ErrorKind::InvalidData, e))
}
}
impl<R: Read> ReadNumeric<f64> for BufReader<R> {
fn read_numeric(&mut self) -> io::Result<f64> {
let mut buf = [0; 8];
self.read_exact(&mut buf)?;
Ok(f64::from_ne_bytes(buf))
}
}
trait ReadVector<T> {
fn read_vector(&mut self, n: usize) -> io::Result<Vec<T>>;
}
impl<T, R: ReadNumeric<T>> ReadVector<T> for R {
fn read_vector(&mut self, n: usize) -> io::Result<Vec<T>> {
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push(self.read_numeric()?);
}
Ok(v)
}
}
// Sparse matrices
struct Matrix<T> {
data: Vec<T>,
indices: Vec<usize>,
indptr: Vec<usize>,
shape: (usize, usize),
}
impl<T> Matrix<T> {
fn read(path: &str) -> io::Result<Self>
where BufReader<File>: ReadNumeric<usize> + ReadNumeric<T>
{
let mut f = BufReader::new(File::open(path)?);
let rows = ReadNumeric::<usize>::read_numeric(&mut f)?;
let cols = ReadNumeric::<usize>::read_numeric(&mut f)?;
let nnz = ReadNumeric::<usize>::read_numeric(&mut f)?;
Ok(Matrix {
data: f.read_vector(nnz)?,
indices: ReadVector::<usize>::read_vector(&mut f, nnz)?,
indptr: ReadVector::<usize>::read_vector(&mut f, rows + 1)?,
shape: (rows, cols),
})
}
}
fn main() {
let _m = Matrix::<f64>::read("matrix.dat");
}
While if I drop the fully qualified syntax, the code does not compile any more (whether stable, or nightly):
impl<T> Matrix<T> {
fn read(path: &str) -> io::Result<Self>
where BufReader<File>: ReadNumeric<usize> + ReadNumeric<T>
{
let mut f = BufReader::new(File::open(path)?);
let rows = f.read_numeric()?;
let cols = f.read_numeric()?;
let nnz = f.read_numeric()?;
Ok(Matrix {
data: f.read_vector(nnz)?,
indices: f.read_vector(nnz)?,
indptr: f.read_vector(rows + 1)?,
shape: (rows, cols),
})
}
}
The compiler cannot deduce that it should use read_numeric<usize>
for rows
, cols
, nnz
, etc., albeit there is no ambiguity what types they should be. Say, (rows, cols)
is used in the shape field, which has type (usize, usize)
. Is automatic type inference in this case something that can be added to the compiler, or are there design reason for why that can't be done?