![](/img/trans.png)
[英]Rust trait object in tuple --- expected trait object, found type
[英]“Expected trait A, found &A” when trying to box a trait object
我正在嘗試制作一個特征,該特征可以檢索(並返回對)另一個特征的一個特征對象,或者創建一個特征(並返回其盒裝版本),將選擇留給實現者(這意味着我需要將返回的對象的生存期限制為生產者的生存期)。 但是,我遇到了錯誤:
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()))
}
}
錯誤是:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | self.get(name).map(|borrow| Box::new(borrow.borrow()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait A, found &A
|
= note: expected type `std::option::Option<std::boxed::Box<dyn A + 'a>>`
found type `std::option::Option<std::boxed::Box<&dyn A>>`
這讓我感到困惑,因為我希望&A
也等於A
我嘗試將impl<'a> A for &'a A
,但這也無濟於事。 有沒有什么辦法解決這一問題?
...可以檢索(或返回對)另一個特征的一個特征對象,或創建一個(並返回其盒裝版本)。
有了此要求, Box
將無法工作。 Box
擁有其數據,但有時您已借用了數據,無法移動。
標准庫中有一個類型叫做Cow
,它是關於值是借來的還是擁有的抽象。 但是,它在這里可能不太適合您,因為它不允許您將數據作為Box
,並且還要求您的數據類型必須實現ToOwned
。
但是我們可以接受您的要求並將其直接建模為enum
:
enum BoxOrBorrow<'a, T: 'a + ?Sized> {
Boxed(Box<T>),
Borrowed(&'a T),
}
並通過實現Deref
使其符合人體工程學:
use std::ops::Deref;
impl<'a, T> Deref for BoxOrBorrow<'a, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
BoxOrBorrow::Boxed(b) => &b,
BoxOrBorrow::Borrowed(b) => &b,
}
}
}
這使您可以將自定義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()))
}
}
您可以通過實現使原來的代碼編譯A
為&'_ dyn A
和添加有明確的轉換:
self.get(name).map(|borrow| Box::new(borrow.borrow()) as Box<dyn A>)
封鎖不是強制性的場所 。 編譯器查看閉包的內容以查看返回值是什么,並得出結論,它返回Box<&'a dyn A>
。 但是閉包本身不能從“函數返回Box<&'a dyn A>
”強制轉換為“函數返回Box<dyn A + 'a>
”,因為這些類型在結構上是不同的。 您添加了強制類型轉換,以告知編譯器您希望閉包首先返回Box<dyn A>
。
但這有點愚蠢。 Box
荷蘭國際集團的基准是完全沒有必要在這里,並澆鑄到Box<dyn A>
只是增加了對呼叫者間接另一個層次。 這將是更好的回報封裝“ 無論是盒裝特質的對象, 或者性狀對象的引用”的概念,作為一種彼得·霍爾的答案描述。
在帶有通用關聯類型(“ GAT”)的Rust的未來版本中,可以使返回類型成為ProducerOrContainer
的關聯類型,如下所示:
trait ProducerOrContainer {
type Result<'a>: A;
fn get_a<'a>(&'a self, name: &'a str) -> Option<Result<'a>>;
}
使用此特征定義,實現ProducerOrContainer
每種類型都可以選擇其返回的類型,因此可以為某些impl
選擇Box<dyn A>
為其他暗示選擇&'a dyn A
。 但是,這在當前的Rust(1.29)中是不可能的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.