如何在相关类型中指定生命周期?

时间:2015-06-19 07:40:47

标签: syntax rust traits lifetime associated-types

我正在尝试让每个GraphicsContext实现返回Shader的不同实现。

pub trait Resources {
    type Shader: shader::Shader;
}

pub trait GraphicsContext {

    type Resources: Resources;

    /// Creates a shader object
    fn create_shader<'a>(&'a self, shader::Stage, source: &str)
        -> Result<<<Self as GraphicsContext>::Resources as Resources>::Shader,
                  shader::CreateError>;

    /// Creates a shader program object
    fn create_shader_program<'a>(&'a self, shaders: Vec<&shader::Shader>)
        -> Result<Box<shader::ShaderProgram + 'a>, shader::ProgramCreateError>;

    // more to come

}

这样create_shader_program方法(和其他方法)知道Shader的具体类型,以便它们可以在着色器对象上调用特定于实现的方法。

我不想将这些方法(例如setCurrentattach)放入所有实现必须使用的特征中。并非所有图形API都使用相同的系统:OpenGL是绑定/解除绑定,Vulkan是结构/设置字段,DirectX是其他等等。

首先,我问这是构建引擎的正确方法。我相信在我的框架/应用程序级代码中需要这些Shader对象,我可以指定具体的类型基于Context的当前类型。

// almost certain this doesn't compile, but should be possible in theory
// I'm trying to say:
// the type of the `shader` argument must match to the associated type
// contained within the `context`
fn do_something_with_shader(context: &GraphicsContext,
                            shader: ??**GraphicsContext::Resources::Shader**??)
                           -> Result<Foo, Bar>;

或者也许:

fn do_something_with_shader<T>(context: &GraphicsContext<T>,
                               shader: ??**T::Shader**??)
    where T: GraphicsContext::Resources -> Result<Foo, Bar>;

这样的事情可能吗?希望你能看到我理解基本的泛型(我来自Java),但这让我感到疯狂(它确实感觉非常 hackish)。

如果这是正确的方法,那么我的实施就会出现问题。 rustc希望关联的类型具有指定的生命周期。

wrong number of lifetime parameters: expected 1, found 0 [E0107]
opal_driver_gl/src/context.rs:23     type Shader = Shader;

我的OpenGLShader结构实际上是OpenGLShader<'a>类型,所以错误是有道理的。我的问题是,从这堆代码中我可以从哪里获得生命周期:

struct OpenGLResources;

impl Resources for OpenGLResources {
    type Shader = OpenGLShader;
}

impl GraphicsContext for OpenGLGraphicsContext {

    type Resources = Resources;

    /// Creates a shader object
    fn create_shader<'a>(&'a self, stage: core_shader::Stage, source: &str)
        -> Result<<<Self as GraphicsContext>::Resources as Resources>::Shader,
                  core_shader::CreateError> {
       // impl goes here
    }

}

我尝试将生命周期附加到OpenGLResourcesOpenGLGraphicsContext,这解决了错误,但后来说error: parameter 'a is never used

所以其次,我问我如何在相关类型中包含该生命周期。

非常感谢,如果你能看一下这个。我觉得这样的东西必须可以在编译时检查,但我对Rust很新,所以我不太理解如何实现它。

1 个答案:

答案 0 :(得分:0)

我最终切换到泛型,这提供了一个成功的实现。

鉴于Resources<'a>,我可以像这样定义GraphicsContext

trait GraphicsContext<'a, R: Resources<'a>>

'a

中的Shader<'a>ShaderProgram<'a>结构需要2 Resources个生命周期

然后可以提供OpenGL实现。请注意,Resources已更改为OpenGLResources

                             // replaced here
impl<'a> GraphicsContext<'a, OpenGLResources<'a>> for OpenGLGraphicsContext<'a> {

    fn create_shader(&'a self, ty: Type, source: &str) -> Result<Shader<'a>, ShaderCreationError> {
        // do something
    }

}