如何根据泛型类型参数给出不同的值?

时间:2018-05-29 12:55:20

标签: rust

我正在尝试按照TheChernoProject Series on openGL实现VertexBufferLayout结构。我已经足够轻松地将C ++系列改编为Rust,但我已经卡住了。

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

我似乎无法接受函数来接受匹配类型的代码。当我收到错误时,我尝试使用TypeIdAnyPhantomData

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'可能活不够长,但它只是一个通用函数,而float只指定了一个被保存的数字,而不是一个类型本身,所以我试图PhantomData。之后的任何错误都让我不知道我在做什么,之前从未使用过PhantomData,也找不到任何适合这种情况的事情。

1 个答案:

答案 0 :(得分:2)

执行编译器建议的工作对我来说很好:

  

help:考虑添加显式生存期限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() {} ...

match

在Rust的未来版本中,您可以使用#![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`
select 
    WIL.ID,
    WAO.[System.WorkItemType],
    WIL.[Created Date],
    WAO.[System.CreatedBy],
    WAO.[System.AssignedTo],
    WIL.[Changed Date],
    WAO.[System.ChangedBy],
    WAO.[System.State],
    WAO.[System.Reason],
    WAO.[System.Title],
    (select top 1 left(REPLACE(REPLACE(replace(Words, ',', '\,'), CHAR(13), ' '), CHAR(10), ' '), 32000) from [dbo].[WorkItemLongTexts] where ID = WIL.ID and FldID = 52 order by AddedDate desc) [Description],
    (select top 1 left(REPLACE(REPLACE(replace(Words, ',', '\,'), CHAR(13), ' '), CHAR(10), ' '), 32000) from [dbo].[WorkItemLongTexts] where ID = WIL.ID and FldID = 54 order by AddedDate desc) [LastComment]
from 
    [dbo].[WorkItemsLatest] WIL
    inner join [dbo].[WorkItemsAsOf] WAO on WAO.[System.Id] = WIL.ID AND WAO.[System.Rev] = WIL.Rev
where 
    WAO.[System.TeamProject] = @ProjectName
order by
    WIL.[Created Date] ASC