【问题标题】:Rust: conversion from generic with trait bound affects trait object typeRust:从具有特征绑定的泛型转换会影响特征对象类型
【发布时间】:2022-12-03 21:37:42
【问题描述】:

我正在用 Rust 开发一个简单的 opengl 包装器库。

我使用 nalgebra_glm crate 进行数学运算。许多类型都实现了 AsRef 以访问底层数组。我为匹配常见矩阵大小的数组类型手动实现了 Uniform,如 [[T; 4]; 4]、[T; 16]、[T; 3] 等。

所以我可以通过调用 Box::new(<nalgebra_glm matrix or vector>.as_ref().clone()) 获得一个新的 Box<dyn Uniform> 但它不必要地冗长。

我想创建一个方便的函数,将任何 &[T](即 Clone 和 AsRef)转换为实现 Uniform 的某种类型 U 到 Vec<Box<dyn Uniform>>。类似于 ToOwned 特征。

这是我想出的。

pub trait Uniform {
    fn bind(&self, location: GLint);
}
pub fn to_owned<U: Uniform + Clone, T: AsRef<U>>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
where Vec<Box<dyn Uniform>>: FromIterator<Box<U>>
{
    uniforms.into_iter()
        .map(AsRef::as_ref)
        .map(Clone::clone)
        .map(Box::new)
        .collect()
}

但是当我尝试在以下上下文中使用此函数时,它导致了我难以理解的错误。

perspective_matrix() 和view_matrix() 都是Mat4 类型并提供AsRef&lt;[[f32; 4]; 4]。

let common_uniforms = to_owned(&[camera.perspective_matrix(), camera.view_matrix()]);
error[E0277]: the trait bound `(dyn Uniform + 'static): Clone` is not satisfied
   --> src\main.rs:167:27
    |
167 |     let common_uniforms = to_owned(&[camera.perspective_matrix(), camera.view_matrix()]);
    |                           ^^^^^^^^ the trait `Clone` is not implemented for `(dyn Uniform + 'static)`
    |
note: required by a bound in `uniform::to_owned`
   --> src\uniform.rs:9:30
    |
9   | pub fn to_owned<U: Uniform + Clone, T: AsRef<U>>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
    |                              ^^^^^ required by this bound in `uniform::to_owned`

为什么生成的特征对象需要 Clone? clone 仅在通用 U 操作期间需要,因此只有 U 应实现 Clone。为什么它与最终特征对象有任何关系?我希望因为U实现了Uniform,所以应该可以从中创建一个dyn Uniform特征对象。

此外,我不能要求 Clone 作为 Uniform 的超级特征,因为它会使它不安全。

我已经尝试将结果框类型显式转换为 trait 对象,添加 'static lifetime bound 但无济于事。

pub fn to_owned<U: 'static + Uniform + Clone, T: AsRef<U>>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
where Vec<Box<dyn Uniform>>: FromIterator<Box<U>>
{
    uniforms.into_iter()
        .map(AsRef::as_ref)
        .map(Clone::clone)
        .map(|uniform| Box::new(uniform) as Box<dyn Uniform>)
        .collect()
}

我真的不明白我的代码有什么问题。要么是我犯了一些句法错误,要么是我在这里试图完成的事情存在更深层次的逻辑错误。

我将不胜感激任何帮助。

【问题讨论】:

  • 你的代码片段真的不是完整的minimal reproducible example,提供一个虚拟的camera和适当的uses 外部类型(GLint,Mat4?,...)所以我们可以运行你的例如,我们自己查看错误并处理它。

标签: rust


【解决方案1】:

主要问题是您的to_owned 功能。

使用 where Vec&lt;Box&lt;dyn Uniform&gt;&gt;: FromIterator&lt;Box&lt;U&gt;&gt; 你实际上隐藏了真正的问题,导致非常混乱的编译器消息。

您添加它可能是因为编译器建议它。但编译器也警告说,虽然这是它所需要的,但添加 where 子句可能不是正确的解决方案。 使用 where 子句,无需指定使转换成为可能的正确边界,您只需将问题移出函数即可。我同意编译器认为这是错误的解决方案。

您的第二次尝试几乎是正确的,您所缺少的只是您需要删除 where 子句:

use nalgebra_glm::Mat4;

fn perspective_matrix() -> Mat4 {
    todo!()
}

pub trait Uniform {
    fn bind(&self, location: i32);
}

impl Uniform for [[f32; 4]; 4] {
    fn bind(&self, _location: i32) {
        todo!()
    }
}

pub fn to_owned<T, U>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
where
    T: AsRef<U>,
    U: Uniform + Clone + 'static,
{
    uniforms
        .into_iter()
        .map(AsRef::as_ref)
        .map(Clone::clone)
        .map(Box::new)
        .map(|b| b as Box<dyn Uniform>)
        .collect()
}

fn main() {
    let _common_uniforms = to_owned(&[perspective_matrix()]);
}

此外,这是一个最小的可重现示例的样子;)

【讨论】:

    猜你喜欢
    • 2022-10-05
    • 2023-01-12
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    • 2019-10-23
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多