0
votes

I am looking to implement 2D matrix functionality in Rust in a generic fashion where the elements of the matrix would be numerics (either i32, i64, u32, u64, f32, f64). The generic type would look something like shown below:

#[derive(Debug)]
pub struct Mat<T> {
    data: Vec<T>,
    shape: (usize, usize),
}

impl<T> Mat<T> where T: i32 OR i64 OR u32 OR u64 OR f32 OR f64{
    pub fn new(){
        ...
    }
}

I know that you can AND trait bounds with the + symbol in the form of "where T: bound1 + bound2". Is there a way to cleanly OR trait bounds together?

2
Note: For this specific case, you probably just want to use the num crate's num::Num trait (or the same thing from num_traits to limit to just the traits, not the rest of num) to just allow any numeric type if you want to support arbitrary numeric types. Or use the specific std::ops traits to specify which operations must be supported without specifically requiring something that num defines the traits for (or for non-builtins, something that implements the traits from num).ShadowRanger
I think the question could be better phrased. It is not about trait bounds. i32 and i64 a types (not traits) and could also not be combined with + to a trait bound. There is a way to implement a trait for a fixed list of types, but this is also not what you want. I would like to encourage you to look at the operations you need and just express them as types. E.g. the traits in std::ops or the num_traits crate.Markus Klein

2 Answers

1
votes

No, but this isn't usually what you want anyway. You can do this by declaring a tag trait, like:

pub trait NumberType {}

impl NumberTrait for i32 {}
impl NumberTrait for i64 {}
// and so on...

impl<T> Mat<T> where T: NumberType { ... }

However, usually what you're actually trying to accomplish is enforcing that T supports some set of operations like addition and multiplication. If so, just bound on those operations:

use std::ops::*;

impl<T> Mat<T> where T: Add<T, Output=T> + Mul<T, Output=T> { ... }

This will cover all of the primitive numeric types, but will also cover other types for which those operations are defined, such as third-party "decimal" or "big number" (e.g. 128/256/512-bit integers) types.

0
votes

If all you need is disjunction between concrete types (and not traits) you just need to create a trait that all those types will implement:

trait Trait {}
impl Trait for i32 {}
impl Trait for u32 {}
// Etc.

impl<T: Trait> Mat<T> {
    // ...
}