[英]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]
Clone
和AsRef
转换为实现Uniform
的某种类型U
到Vec<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.