我可以在 Rust 中使用泛型函数参数来创建新变量吗?

Joh*_*ohn 3 generics rust

是否可以在 Rust 中创建泛型参数类型的实例?

我来自 C++ 背景,使用模板类型在实际函数体中创建类型是完全有效的。

我正在尝试T在此函数中创建一个具有类型的变量,但我不确定如何。

我只想能够创建一个 type 的对象T,加载它,然后将它插入到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));
}
Run Code Online (Sandbox Code Playgroud)

这是我的所有代码:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

mal*_*rbo 5

在 C++ 中,当您声明一个变量时,就像T asset;您假设的那样T具有默认构造函数(鸭子类型的编译时版本)。T使用没有默认构造函数的类型实例化是编译器错误,但如果没有发生这样的实例化也没关系。

在 Rust 中,您不能“假设”类型参数支持操作。您必须在类型参数上指定受支持的操作。

也就是说,您必须选择:

定义您自己的构造函数,如关联函数 AssetTrait

例如,您可以声明load为不带self参数并返回的关联函数Self,并调用T::load(path)实例化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));
    }
}
Run Code Online (Sandbox Code Playgroud)

使用具有类似关联函数的构造函数的预定义特征

在 Rust 中,Default特性用于此目的:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 小提示:在 impl 块中分解的每个 fn 都是一个关联的 fn。对于那些采用 self 的方法,我们有一个更具体的名称,但方法是关联的函数。 (2认同)