首页 > 解决方案 > 如何根据泛型类型参数给出不同的值?

问题描述

我正在尝试按照openGL 上的 TheChernoProject SeriesVertexBufferLayout来实现一个结构。我已经很容易地将 C++ 系列改编为 Rust,但我被卡住了。

VertexBufferElement有一个计数,它使用的 glEnumdata_type和一个标准化的布尔值。有一个称为通用方法的方法push,它采用 u32 计数,将 VertexBufferElement 推送到元素 Vec 并更新步幅。

我似乎无法让函数接受匹配类型的代码。我尝试使用TypeId,AnyPhantomData当我遇到错误时。

pub fn push<T: 'a>(&mut self, count: u32) {
    let dt = TypeId::of::<T>();
    let (data_type, normalized) = if dt == TypeId::of::<i8>() {
        (gl::BYTE, false)
    } else if dt == TypeId::of::<u8>() {
        (gl::UNSIGNED_BYTE, true)
    } else if dt == TypeId::of::<i16>() {
        (gl::SHORT, false)
    } else if dt == TypeId::of::<u16>() {
        (gl::UNSIGNED_SHORT, false)
    } else if dt == TypeId::of::<i32>() {
        (gl::INT, false)
    } else if dt == TypeId::of::<u32>() {
        (gl::UNSIGNED_INT, false)
    } else if dt == TypeId::of::<f16>() {
        (gl::HALF_FLOAT, false)
    } else if dt == TypeId::of::<f32>() {
        (gl::FLOAT, false)
    } else if dt == TypeId::of::<f64>() {
        (gl::DOUBLE, false)
    } else {
        panic!("Incompatible Type")
    };
    self.elements.push(VertexBufferElement{data_type, count, normalized, _marker: PhantomData});
    self.stride += mem::size_of::<T>();
}

vertex_buffer_layout.rs

    error[E0310]: the parameter type `T` may not live long enough
  --> opengl\examples\vertex_buffer_layout.rs:26:18
   |
25 |     pub fn push<T: 'a>(&mut self, count: u32) {
   |                 -- help: consider adding an explicit lifetime bound `T: 'static`...
26 |         let dt = TypeId::of::<T>();
   |                  ^^^^^^^^^^^^^^^
   |
note: ...so that the type `T` will meet its required lifetime bounds
  --> opengl\examples\vertex_buffer_layout.rs:26:18
   |
26 |         let dt = TypeId::of::<T>();
   |  

起初它是 'T​​' 可能活得不够长,但它只是一个通用函数,并且浮点数只指示保存的数字,而不是类型本身,所以我尝试了PhantomData. 之后的任何错误都是我不知道自己在做什么,以前从未使用PhantomData过,也找不到适合这种情况的任何东西。

标签: rust

解决方案


做编译器建议的事情对我来说很好:

帮助:考虑添加一个明确的生命周期限制T: 'static......

use std::any::TypeId;

enum Type {
    Byte,
    Short,
}

fn decide<T: 'static>() -> (Type, bool) {
    let dt = TypeId::of::<T>();

    if dt == TypeId::of::<u8>() {
        (Type::Byte, false)
    } else if dt == TypeId::of::<u16>() {
        (Type::Short, true)
    } else {
        panic!("Unknown type")
    }
}

fn main() {}

在 Rust 的未来版本中,您可以使用match表达式来缩短它:

#![feature(const_type_id)]

fn decide<T: 'static>() -> (Type, bool) {
    const ID_U8: TypeId = TypeId::of::<u8>();
    const ID_U16: TypeId = TypeId::of::<u16>();

    match TypeId::of::<T>() {
        ID_U8 => (Type::Byte, false),
        ID_U16 => (Type::Short, true),
        _ => panic!("Unknown type"),
    }
}

我宁愿不允许运行时失败,但是:

enum Type {
    Byte,
    Short,
}

trait AsType {
    fn as_type() -> (Type, bool);
}

impl AsType for u8 {
    fn as_type() -> (Type, bool) {
        (Type::Byte, false)
    }
}

impl AsType for u16 {
    fn as_type() -> (Type, bool) {
        (Type::Short, true)
    }
}

fn main() {
    u8::as_type();   // Ok
    bool::as_type(); // Error
}
error[E0599]: no function or associated item named `as_type` found for type `bool` in the current scope
  --> src/main.rs:24:5
   |
24 |     bool::as_type();
   |     ^^^^^^^^^^^^^ function or associated item not found in `bool`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `as_type`, perhaps you need to implement it:
           candidate #1: `AsType`

推荐阅读