简体   繁体   English

Rust:从具有特征绑定的泛型转换影响特征 object 类型

[英]Rust: conversion from generic with trait bound affects trait object type

I'm working on a simple opengl wrapper library in rust.我正在 rust 中开发一个简单的 opengl 包装器库。

Im using nalgebra_glm crate for the math operations.我使用nalgebra_glm crate 进行数学运算。 Lots of types implement AsRef for the access to the underlying array.许多类型实现AsRef以访问底层数组。 I manually implemented Uniform for array types that match common matrix sizes like [[T; 4]; 4]我为匹配常见矩阵大小的数组类型手动实现了Uniform ,例如[[T; 4]; 4] [[T; 4]; 4] [[T; 4]; 4] , [T; 16] [[T; 4]; 4] , [T; 16] [T; 16] , [T; 3] [T; 16] , [T; 3] [T; 3] and so on. [T; 3]等等。

So I can obtain a new Box<dyn Uniform> by calling Box::new(<nalgebra_glm matrix or vector>.as_ref().clone()) but it's unnecessarily verbose.所以我可以通过调用Box::new(<nalgebra_glm matrix or vector>.as_ref().clone())获得一个新的Box<dyn Uniform>但它不必要地冗长。

I wanted to create a convenience function that converts any &[T] which is Clone and AsRef to some type U that implements Uniform into Vec<Box<dyn Uniform>> .我想创建一个方便的 function 将任何&[T] CloneAsRef转换为实现Uniform的某种类型UVec<Box<dyn Uniform>> Something similar to ToOwned trait.类似于ToOwned特征的东西。

Here's what I came up with.这是我想出的。

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()
}

But then when I tried using this function in the following context it caused and error which I'm struggling to understand.但是当我尝试在以下上下文中使用这个 function 时,它导致了我很难理解的错误。

perspective_matrix() and view_matrix() are both of type Mat4 and provide a AsRef<[[f32; 4]; 4] perspective_matrix()view_matrix()都是Mat4类型并提供AsRef<[[f32; 4]; 4] AsRef<[[f32; 4]; 4] AsRef<[[f32; 4]; 4] . AsRef<[[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`

Why is Clone required by the resulting trait object?为什么生成的特征 object 需要Clone clone is only needed during operations on generic U and thus only U should implement Clone .仅在对通用U进行操作期间才需要clone ,因此只有U应实现Clone Why does it have anything to do with the final trait object?为什么它与最终特征 object 有任何关系? I would expect that since U implements Uniform it should be possible to create a dyn Uniform trait object out of it.我希望由于U实现了Uniform ,所以应该可以从中创建一个动态dyn Uniform特征 object。

Also I cannot require Clone as super trait for Uniform since it would make it not object safe.此外,我不能要求Clone作为Uniform的超级特征,因为它会使 object 不安全。

I have tried explicitly casting resulting box type into trait object, adding 'static lifetime bound but to no avail.我已经尝试将结果框类型显式转换为特征 object,添加'static生命周期绑定但无济于事。

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()
}

I really don't understand what's wrong with my code.我真的不明白我的代码有什么问题。 It's either that I'm doing some syntactic mistake or there's deeper logical error with what I'm trying to accomplish here.要么是我犯了一些句法错误,要么是我在这里试图完成的事情存在更深层次的逻辑错误。

I would greatly appreciate any help.我将不胜感激任何帮助。

The main problem is your to_owned function.主要问题是您的to_owned function。

With where Vec<Box<dyn Uniform>>: FromIterator<Box<U>> you are actually hiding the real problem, causing very confusing compiler messages.使用where Vec<Box<dyn Uniform>>: FromIterator<Box<U>>你实际上隐藏了真正的问题,导致非常混乱的编译器消息。

You probably added this because the compiler suggested it.您添加它可能是因为编译器建议它。 But the compiler also warns that while this is what it needs, adding the where clause is probably not the correct solution.但是编译器也警告说,虽然这是它所需要的,但添加where子句可能不是正确的解决方案。 With the where clause, instead of specifying correct bounds that make the conversion possible, you just move the problem out of the function. I agree with the compiler that this is the wrong solution.使用where子句,而不是指定使转换成为可能的正确界限,您只需将问题移出 function。我同意编译器,这是错误的解决方案。

Your second attempt is almost correct, all you are missing is that you need to remove the where clause:您的第二次尝试几乎是正确的,您所缺少的只是您需要删除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(|uniform| Box::new(uniform) as Box<dyn Uniform>)
        .collect()
}

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

Also, this is how a minimal reproducible example looks like;)此外,这是一个最小的可重现示例的样子;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM