无法将实现特征的结构装箱为特征对象
Can't box a struct that implements a trait as a trait object
我正在玩 Rust,这里是代码:
pub trait TFilter {
fn get_text(&self) -> &String;
}
...
pub struct ContentFilter {
text: String,
domains: String,
body: String,
}
impl TFilter for ContentFilter {
fn get_text(&self) -> &String {
return &self.text
}
}
impl ContentFilter {
pub fn from_text(text: String, domains: String, body: String) -> Self {
return ContentFilter {
text,
domains,
body
}
}
}
...
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter> {
...
&Box::new(ContentFilter::from_text(text, domains, body)) // is returned
...
}
我收到错误消息:
expected trait object dyn filter::TFilter
, found struct filter::ContentFilter
= note: expected reference &std::boxed::Box<(dyn filter::TFilter + 'static)>
found reference &std::boxed::Box<filter::ContentFilter>
这是误导性的:
- 它确实实现了特征
- 编译器确实知道
ContentFilter
struct 的大小
有线索吗?
PS。代码无论如何都不好(因为不清楚谁拥有返回的 Box),但消息具有误导性。
PPS。那么如何实现缓存代理:
pub trait TFilterBuilder {
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter>;
}
...
struct FilterCachingProxy {
filter_builder: Box<dyn TFilterBuilder>,
cache: Box<dyn TFilterCache>
}
impl FilterCachingProxy {
fn new_for_builder(filter_builder: Box<dyn TFilterBuilder>, cache: Box<dyn TFilterCache>) -> Self {
return FilterCachingProxy {
filter_builder,
cache
}
}
}
impl TFilterBuilder for FilterCachingProxy {
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter> {
let boxed_filter = match self.cache.get(&text) {
Some(found_boxed_filter) => found_boxed_filter,
_ => {
// delegate creation to wrapped TFilterBuilder impl (`filter_builder`)
let boxed_filter = self.filter_builder.filter_from_text(text.clone());
// ... and put to the cache
self.cache.put(&text, &boxed_filter); // boxed_filter should be moved to make cache own it?
&boxed_filter // looks strange: who owns it then?
}
};
return boxed_filter;
}
}
return 类型应该只是一个 Box
,而不是对 Box
的引用:
fn filter_from_text(&mut self, text: String) -> Box<dyn TFilter> {
...
Box::new(ContentFilter::from_text(text, domains, body)) // is returned
}
(Minimal compiling version on the playground)
盒子是在您的函数中新创建的,因此您必须 return 盒子的所有权。不可能只是 return 对临时对象的引用,因为它会在函数结束时超出范围。
此更改的一个副作用是从 Box<ContentFilter>
到 Box<dyn TFilter>
的无限制强制转换现在将真正起作用。强制转换仅适用于 强制转换站点 ,如 return 值。在您的代码中,需要强制转换的类型嵌套在引用中,因此编译器不会执行未确定大小的强制转换。
我正在玩 Rust,这里是代码:
pub trait TFilter {
fn get_text(&self) -> &String;
}
...
pub struct ContentFilter {
text: String,
domains: String,
body: String,
}
impl TFilter for ContentFilter {
fn get_text(&self) -> &String {
return &self.text
}
}
impl ContentFilter {
pub fn from_text(text: String, domains: String, body: String) -> Self {
return ContentFilter {
text,
domains,
body
}
}
}
...
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter> {
...
&Box::new(ContentFilter::from_text(text, domains, body)) // is returned
...
}
我收到错误消息:
expected trait object
dyn filter::TFilter
, found structfilter::ContentFilter
= note: expected reference
&std::boxed::Box<(dyn filter::TFilter + 'static)>
found reference&std::boxed::Box<filter::ContentFilter>
这是误导性的:
- 它确实实现了特征
- 编译器确实知道
ContentFilter
struct 的大小
有线索吗?
PS。代码无论如何都不好(因为不清楚谁拥有返回的 Box),但消息具有误导性。
PPS。那么如何实现缓存代理:
pub trait TFilterBuilder {
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter>;
}
...
struct FilterCachingProxy {
filter_builder: Box<dyn TFilterBuilder>,
cache: Box<dyn TFilterCache>
}
impl FilterCachingProxy {
fn new_for_builder(filter_builder: Box<dyn TFilterBuilder>, cache: Box<dyn TFilterCache>) -> Self {
return FilterCachingProxy {
filter_builder,
cache
}
}
}
impl TFilterBuilder for FilterCachingProxy {
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter> {
let boxed_filter = match self.cache.get(&text) {
Some(found_boxed_filter) => found_boxed_filter,
_ => {
// delegate creation to wrapped TFilterBuilder impl (`filter_builder`)
let boxed_filter = self.filter_builder.filter_from_text(text.clone());
// ... and put to the cache
self.cache.put(&text, &boxed_filter); // boxed_filter should be moved to make cache own it?
&boxed_filter // looks strange: who owns it then?
}
};
return boxed_filter;
}
}
return 类型应该只是一个 Box
,而不是对 Box
的引用:
fn filter_from_text(&mut self, text: String) -> Box<dyn TFilter> {
...
Box::new(ContentFilter::from_text(text, domains, body)) // is returned
}
(Minimal compiling version on the playground)
盒子是在您的函数中新创建的,因此您必须 return 盒子的所有权。不可能只是 return 对临时对象的引用,因为它会在函数结束时超出范围。
此更改的一个副作用是从 Box<ContentFilter>
到 Box<dyn TFilter>
的无限制强制转换现在将真正起作用。强制转换仅适用于 强制转换站点 ,如 return 值。在您的代码中,需要强制转换的类型嵌套在引用中,因此编译器不会执行未确定大小的强制转换。