Rust &引用;预期性状A、已发现和;A「;尝试框选特征对象时

Rust &引用;预期性状A、已发现和;A「;尝试框选特征对象时,rust,trait-objects,Rust,Trait Objects,我试图创建一个trait,它可以检索(并返回对另一个trait的引用)trait对象,也可以创建一个trait对象(并返回它的装箱版本),将选择权留给实现者(这意味着我需要将返回对象的生存期限制为生产者的生存期)。但是,我遇到了一些错误: use std::borrow::Borrow; use std::collections::HashMap; trait A { fn foobar(&self) { println!("!"); } } t

我试图创建一个trait,它可以检索(并返回对另一个trait的引用)trait对象,也可以创建一个trait对象(并返回它的装箱版本),将选择权留给实现者(这意味着我需要将返回对象的生存期限制为生产者的生存期)。但是,我遇到了一些错误:

use std::borrow::Borrow;
use std::collections::HashMap;

trait A { 
    fn foobar(&self) {
        println!("!"); 
    } 
}

trait ProducerOrContainer {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<Box<dyn A + 'a>>;
}

impl<'b, B: Borrow<A>> ProducerOrContainer for HashMap<&'b str, B> {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<Box<dyn A + 'a>> {
        self.get(name).map(|borrow| Box::new(borrow.borrow()))
    }
}
使用标准::借用::借用;
使用std::collections::HashMap;
性状A{
fn foobar(&self){
println!(“!”);
} 
}
特性生产容器{
fn获得_a>;
}
恳求{
fn获得_a>{
self.get(name).map(|借用| Box::new(借用.借用()))
}
}
错误是:

错误[E0308]:类型不匹配
-->src/main.rs:20:9
|
20 | self.get(name).map(| borrow | Box::new(borrow.borrow()))
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
=注意:对于&'A A
,类型应为'std::option::option A,但这也没有帮助。有办法解决这个问题吗

…可以检索(并返回对)另一个trait的trait对象的引用,或创建一个trait对象(并返回其装箱版本)

根据此要求,
将不起作用。一个
拥有它的数据,但有时你会借用数据,而这些数据你无法移动

标准库中有一个类型称为,它是关于值是借用还是拥有的抽象。但是,它可能不太适合您,因为它不允许您将数据作为
拥有,而且它还要求您的数据类型必须实现
ToOwned

但我们可以将您的需求直接建模为
enum

enum BoxOrBorrow<'a, T: 'a + ?Sized> {
    Boxed(Box<T>),
    Borrowed(&'a T),
}
这使您可以将自定义的
BoxOrBorrow
类型视为任何其他引用-您可以使用
*
解除对它的引用,或将其传递给任何需要引用
T
的函数

这是您的代码的外观:

trait ProducerOrContainer {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>>;
}

impl<'b, B: Borrow<dyn A>> ProducerOrContainer for HashMap<&'b str, B> {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>> {
        self.get(name)
            .map(|b| BoxOrBorrow::Borrowed(b.borrow()))
    }
}
trait producercontainer{
fn为HashMap(&'a self,name:&'a str)->选项获取一个producercontainer{
self.get(名称)
.map(| b | BoxOrBorrow::借用(b.borrow()))
}
}
…可以检索(并返回对)另一个trait的trait对象的引用,或创建一个trait对象(并返回其装箱版本)

根据此要求,
将不起作用。一个
拥有它的数据,但有时你会借用数据,而这些数据你无法移动

标准库中有一个类型称为,它是关于值是借用还是拥有的抽象。但是,它可能不太适合您,因为它不允许您将数据作为
拥有,而且它还要求您的数据类型必须实现
ToOwned

但我们可以将您的需求直接建模为
enum

enum BoxOrBorrow<'a, T: 'a + ?Sized> {
    Boxed(Box<T>),
    Borrowed(&'a T),
}
这使您可以将自定义的
BoxOrBorrow
类型视为任何其他引用-您可以使用
*
解除对它的引用,或将其传递给任何需要引用
T
的函数

这是您的代码的外观:

trait ProducerOrContainer {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>>;
}

impl<'b, B: Borrow<dyn A>> ProducerOrContainer for HashMap<&'b str, B> {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>> {
        self.get(name)
            .map(|b| BoxOrBorrow::Borrowed(b.borrow()))
    }
}
trait producercontainer{
fn为HashMap(&'a self,name:&'a str)->选项获取一个producercontainer{
self.get(名称)
.map(| b | BoxOrBorrow::借用(b.borrow()))
}
}

您可以通过为
&“dyn A
实现
A
并添加显式强制转换来编译原始代码:

self.get(name).map(|borrow| Box::new(borrow.borrow()) as Box<dyn A>)

使用此特征定义,实现
producercontainer
的每个类型都可以选择它返回的类型,因此您可以为一些
impl
选择
Box
,为其他
选择一个dyn a
。但是,这在当前的Rust(1.29)中是不可能的。

您可以通过为
&“dyn A
实现
A
并添加显式强制转换来编译原始代码:

self.get(name).map(|borrow| Box::new(borrow.borrow()) as Box<dyn A>)

使用此特征定义,实现
producercontainer
的每个类型都可以选择它返回的类型,因此您可以为一些
impl
选择
Box
,为其他
选择一个dyn a
。然而,这在当前的锈病(1.29)中是不可能的。

A
实现特性并不意味着
&A
实现特性。有时,由于Rust的自动参考和自动取消参考行为,这似乎是真的。例如,它将自动对变量进行排序,这样您就可以键入
foo.bar()
,而不是
(*foo.bar()
),为什么还要返回
框呢?装箱引用似乎不是很有用。我注意到
name:&'a str
在这里受到不必要的约束,因为返回的引用没有绑定到
name
。也许您有其他的
producercontainer
实现,其中返回值是从
name
派生的,但是如果没有,那么去掉
'a
将更加灵活。
a
实现特征并不意味着
&a
就可以。有时,由于Rust的自动参考和自动取消参考行为,这似乎是真的。例如,它将自动对变量进行排序,这样您就可以键入
foo.bar()
,而不是
(*foo.bar()
),为什么还要返回
框呢?装箱引用似乎不是很有用。我注意到
name:&'a str
在这里受到不必要的约束,因为返回的引用没有绑定到
name
。也许您还有其他的
producercontainer
实现,其中返回的值是从
name
派生的,但是如果没有,那么去掉
'a
将更加灵活。