通用寿命参数和本地范围
Piet
是一个带有通用后端的图形库(例如,开罗)。
我想拥有一个特质可渲染的
,可以呈现到任何彼得后端(= context)。
pub trait Renderable {
fn render<C: piet::RenderContext>(&self, ctx: &mut C);
// Since `Renderable` can render to any `RenderContext`, it can render to a file too.
fn save_to_file(&self, path: &Path) {
let ctx = build_cairo_context_for_image_file(path);
self.render::<piet_common::CairoRenderContext>(&mut ctx);
}
}
但是,rustc抱怨渲染&lt; c&gt;
的对象不安全,所以我使特质本身本身通用:
pub trait Renderable<C: piet::RenderContext> {
fn render(&self, ctx: &mut C);
fn save_to_file(&self, path: &Path) -> Result<(), piet_common::Error> {
let width = 512;
let height = 512;
let pix_scale = 1.0;
let mut device = piet_common::Device::new()?;
let mut bitmap: piet_common::BitmapTarget =
device.bitmap_target(width, height, pix_scale)?;
let mut rc = bitmap.render_context();
// Renderable::<CairoRenderContext>::render(self, &mut rc);
self.render(&mut rc);
rc.finish()?;
bitmap.save_to_file(path);
Ok(())
}
}
现在问题是,当save> save_to_to_file
调用self.render(&amp)(&amp) ; mut rc)
,它无法找到该方法,因为save_to_file
是针对c
而不是cairorenderContext
(尽管cairorenderContercontextext)
实施RenderContext
)。
|
14 | pub trait Renderable<C: piet_common::RenderContext> {
| - this type parameter
...
25 | self.render(&mut rc);
| ^^^^^^^ expected type parameter `C`, found struct `CairoRenderContext`
|
= note: expected mutable reference `&mut C`
found mutable reference `&mut CairoRenderContext<'_>`
作为尴尬的解决方法,我添加了针对任何类型的渲染&lt; cairorendercontext&gt;
实现的特征
。问题是cairorenderContext
具有生命周期参数,struct cairorendercontext&lt;'a&gt;
。
pub trait Renderable<C: piet_common::RenderContext> {
fn render(&self, ctx: &mut C);
}
pub trait Drawable {
fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
where
Self: Renderable<CairoRenderContext<'a>>,
{
let width = 512;
let height = 512;
let pix_scale = 1.0;
let mut device = piet_common::Device::new()?;
let mut bitmap: piet_common::BitmapTarget =
device.bitmap_target(width, height, pix_scale)?;
let mut rc = bitmap.render_context();
Renderable::<CairoRenderContext>::render(self, &mut rc);
// self.render(&mut rc);
rc.finish()?;
drop(rc);
bitmap.save_to_file(path);
// at this point, we don't need device, bitmap or rc.
// rustc thinks they should be alive.
Ok(())
}
}
Lifetime 'a
应该代表本地变量设备
但设备
和bitmap
的rustc错误变量应寿命足够长,以便'a
。
1 error[E0597]: `device` does not live long enough
|
| fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
| -- lifetime `'a` defined here
...
| device.bitmap_target(width, height, pix_scale)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
| let mut rc = bitmap.render_context();
| ----------------------- assignment requires that `device` is borrowed for `'a`
...
| }
| - `device` dropped here while still borrowed
2 error[E0597]: `bitmap` does not live long enough
|
| fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
| -- lifetime `'a` defined here
...
| let mut rc = bitmap.render_context();
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| assignment requires that `bitmap` is borrowed for `'a`
...
| }
| - `bitmap` dropped here while still borrowed
3 error[E0505]: cannot move out of `bitmap` because it is borrowed
|
| fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
| -- lifetime `'a` defined here
...
| let mut rc = bitmap.render_context();
| -----------------------
| |
| borrow of `bitmap` occurs here
| assignment requires that `bitmap` is borrowed for `'a`
...
| bitmap.save_to_file(path);
| ^^^^^^ move out of `bitmap` occurs here
- Q1。当Rustc关于对象安全的错误时,是从
渲染&lt; c&gt;
to渲染&lt; c&gt;
中升高类型参数的正确解决方案吗? - Q2。我应该有两个特征(可渲染的,可绘制的),所以
save_to_file
可以调用渲染
,还是有更好的方法? - Q3。我如何正确地告诉Rustc关于
self:在最后一个示例中渲染&lt; cairorendercontext&lt;
piet
is a drawing library with generic backends (cairo, for example).
I want to have a trait Renderable
that can render to any piet backend (=context).
pub trait Renderable {
fn render<C: piet::RenderContext>(&self, ctx: &mut C);
// Since `Renderable` can render to any `RenderContext`, it can render to a file too.
fn save_to_file(&self, path: &Path) {
let ctx = build_cairo_context_for_image_file(path);
self.render::<piet_common::CairoRenderContext>(&mut ctx);
}
}
However rustc complained about object unsafety of render<C>
, so I made the trait itself generic:
pub trait Renderable<C: piet::RenderContext> {
fn render(&self, ctx: &mut C);
fn save_to_file(&self, path: &Path) -> Result<(), piet_common::Error> {
let width = 512;
let height = 512;
let pix_scale = 1.0;
let mut device = piet_common::Device::new()?;
let mut bitmap: piet_common::BitmapTarget =
device.bitmap_target(width, height, pix_scale)?;
let mut rc = bitmap.render_context();
// Renderable::<CairoRenderContext>::render(self, &mut rc);
self.render(&mut rc);
rc.finish()?;
bitmap.save_to_file(path);
Ok(())
}
}
Now the problem is, when save_to_file
calls self.render(&mut rc)
, it cannot find the method because save_to_file
is implemented for C
and not CairoRenderContext
(although CairoRenderContext
implements RenderContext
).
|
14 | pub trait Renderable<C: piet_common::RenderContext> {
| - this type parameter
...
25 | self.render(&mut rc);
| ^^^^^^^ expected type parameter `C`, found struct `CairoRenderContext`
|
= note: expected mutable reference `&mut C`
found mutable reference `&mut CairoRenderContext<'_>`
As an awkward workaround, I added trait Drawable
that is implemented for any type of Renderable<CairoRenderContext>
. The problem is CairoRenderContext
has a lifetime parameter, struct CairoRenderContext<'a>
.
pub trait Renderable<C: piet_common::RenderContext> {
fn render(&self, ctx: &mut C);
}
pub trait Drawable {
fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
where
Self: Renderable<CairoRenderContext<'a>>,
{
let width = 512;
let height = 512;
let pix_scale = 1.0;
let mut device = piet_common::Device::new()?;
let mut bitmap: piet_common::BitmapTarget =
device.bitmap_target(width, height, pix_scale)?;
let mut rc = bitmap.render_context();
Renderable::<CairoRenderContext>::render(self, &mut rc);
// self.render(&mut rc);
rc.finish()?;
drop(rc);
bitmap.save_to_file(path);
// at this point, we don't need device, bitmap or rc.
// rustc thinks they should be alive.
Ok(())
}
}
The lifetime 'a
is supposed to represent the lifetime of a local variable device
but rustc errors that device
and bitmap
variables should live long enough for 'a
.
1 error[E0597]: `device` does not live long enough
|
| fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
| -- lifetime `'a` defined here
...
| device.bitmap_target(width, height, pix_scale)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
| let mut rc = bitmap.render_context();
| ----------------------- assignment requires that `device` is borrowed for `'a`
...
| }
| - `device` dropped here while still borrowed
2 error[E0597]: `bitmap` does not live long enough
|
| fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
| -- lifetime `'a` defined here
...
| let mut rc = bitmap.render_context();
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| assignment requires that `bitmap` is borrowed for `'a`
...
| }
| - `bitmap` dropped here while still borrowed
3 error[E0505]: cannot move out of `bitmap` because it is borrowed
|
| fn save_to_file<'a>(&self, path: &Path) -> Result<(), piet_common::Error>
| -- lifetime `'a` defined here
...
| let mut rc = bitmap.render_context();
| -----------------------
| |
| borrow of `bitmap` occurs here
| assignment requires that `bitmap` is borrowed for `'a`
...
| bitmap.save_to_file(path);
| ^^^^^^ move out of `bitmap` occurs here
- Q1. When rustc errors about object-safety, was it a correct solution to uplift a type parameter from
render<C>
toRenderable<C>
? - Q2. Should I have two traits (Renderable, Drawable) so
save_to_file
can callrender
or is there a better way? - Q3. How can I correctly tell rustc about
Self: Renderable<CairoRenderContext<_>>
in the last example?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
关于
&amp; mut c
和&amp; mut cairorenderContext&lt;'_&gt;
不匹配的第二个错误是通过省略save_to_to_file()从性状定义中,而是在Inplb块中定义它。这是我的意思是一个高度简化的版本:
原始方法在概念上似乎是错误的,因为
可渲染的
特征应该是后端-Agnostic,但是save_to_file()正在使用特定于开罗的类型,从而导致误差。
Q1
将通用性从方法转移到特征确实是制造特质对象安全的一种策略。其他策略是
where self:大小
(尽管您将无法使用动态调度来调用该方法)Q2
您不需要两个特征如果您使用了我描述的方法。
Q3
答案是a 更高排名的性状界限:
注意,您可以使界限成为超级框架:
Your second error, regarding the
&mut C
and&mut CairoRenderContext<'_>
mismatch, is solved by omitting the body ofsave_to_file()
from the trait definition, and instead defining it in the impl block. Here's a highly simplified version of what I mean:The original approach seems conceptually wrong in that the
Renderable
trait is supposed to be backend-agnostic, yet the default impl ofsave_to_file()
was using types specific to Cairo, thus causing the error.Q1
Moving the generic from the method to the trait is indeed one strategy to make a trait object-safe. Other strategies are
where Self: Sized
(though you won't be able to call that method using dynamic dispatch)Q2
You don't need two traits if you used the approach I described.
Q3
The answer is a higher-ranked trait bound:
Note you can make the bound a supertrait instead: