Search code examples
rustblockchaintraitsgeneric-programmingsubstrate

Trait as generic parameter to struct object intialization


I have this struct:

use sp_runtime::traits::Block;

struct Bar<T: Block> {
    e1: Vec<T>,
}

impl<T: Block> Bar<T> {
    pub fn new() -> Self {
        Bar { e1: Vec::new() }
    }
}

Where Block is from the sp_runtime crate.

In main:

fn main() {
    let var_1 = Bar::<Block>::new();
}

Full Code

This code throws compilation error that trait can't be made into an object. I'm new to Rust, much of online solution haven't addressed this issue. Kindly let me know how to get around initialization of bar object.


Solution

  • Your confusion likely stems from the fact that the sp_runtime crate has two items called Block. One is the trait sp_runtime::traits::Block and the other is a struct, sp_runtime::generic::Block, which implements that trait.

    Traits can be used as a constraint on a type parameter, but they cannot be used as a type argument.

    So, in your definition of Bar<T>, you can constrain T with sp_runtime::traits::Block, but when you construct an instance of Bar<T>, T needs to be the struct instead.

    use sp_runtime::traits::Block;
    
    struct<T: Block> Bar {
        e1: Vec<T>,
    } 
       
    impl<T: Block> Bar<T> {
        pub fn new() -> Self {
            Bar {
                e1: Vec::new(),
            }
        }
    } 
    
    fn main() {
        use sp_runtime::generic::Block;
        let var_1 = Bar::<Block>::new();
    }
    

    However, given that this is the only implementation of the trait in the crate, you can just avoid mentioning the trait altogether and use the concrete struct type (unless you plan on implementing it yourself or depending on implementations from other crates):

    use sp_runtime::generic::Block;
    
    struct Bar{
        e1 : Vec<Block>,
    } 
       
    impl Bar {
        pub fn new() -> Self{
            Bar {
                e1: Vec::new(),
            }
        }
    } 
    
    fn main() {
        let var_1 = Bar::new();
    }