简体   繁体   中英

Can I use generic function arguments in Rust to create new variables?

Is it possible to create an instance of a generic parameter type in Rust?

I'm coming from a C++ background where it's perfectly valid to use template types to create types in the actual function body.

I'm trying to create a variable with type T in this function but I'm not sure how.

I just want to be able to create an object of type T , load it, and then insert it into the HashMap :

fn load<T>(&mut self, id: String, path: String)
    where T: AssetTrait + 'static
{
    // let asset : T = T; this doesn't work?

    asset.load(path);

    // self.assets.insert(id, Box::new<T>(asset));
}

Here is all my code:

trait AssetTrait {
    fn load(&self, path: String) {
        // Do nothing
        // Implement this in child asset object
    }
}

struct AssetManager {
    assets: HashMap<String, Box<AssetTrait + 'static>>,
}

impl AssetManager {
    fn new() -> AssetManager {
        let asset_manager = AssetManager { assets: HashMap::new() };

        return asset_manager;
    }

    fn load<T>(&mut self, id: String, path: String)
        where T: AssetTrait + 'static
    {
        // let asset : T = T; this doesn't work?

        asset.load(path);

        // self.assets.insert(id, Box::new<T>(asset));
    }
}

In C++ when you declare a variable like T asset; you are assuming that T has a default constructor (compile time version of duck typing). It is an compiler error to instantiated T with a type that does not have a default constructor, but it's ok if no such instantiation happens.

In Rust you cannot "assume" that a type parameter supports an operation. You have to specify the supported operations with bounds on the type parameter.

That said, you have to options:

Define your own constructor like associated function in AssetTrait

For example, you can declare load as an associated function that do not take a self parameter and returns Self , and call T::load(path) to instantiate T :

use std::collections::HashMap;

trait AssetTrait {
    fn load(path: String) -> Self;
}

struct AssetManager {
    assets: HashMap<String, Box<AssetTrait + 'static>>,
}

impl AssetManager {
    fn new() -> AssetManager {
        let asset_manager = AssetManager { assets: HashMap::new() };
        return asset_manager;
    }

    fn load<T>(&mut self, id: String, path: String)
        where T: AssetTrait + 'static
    {
        let asset = T::load(path);
        self.assets.insert(id, Box::new(asset));
    }
}

Use a predefined trait that has a constructor like associated function

In Rust, the Default trait is used for this purpose:

use std::collections::HashMap;

trait AssetTrait {
    fn load(&mut self, path: String);
}

struct AssetManager {
    assets: HashMap<String, Box<AssetTrait + 'static>>,
}

impl AssetManager {
    fn new() -> AssetManager {
        let asset_manager = AssetManager { assets: HashMap::new() };
        return asset_manager;
    }

    fn load<T>(&mut self, id: String, path: String)
        where T: Default + AssetTrait + 'static
    {
        let mut asset = T::default();
        asset.load(path);
        self.assets.insert(id, Box::new(asset));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM