Hãy tưởng tượng một số nguồn sự kiện, tạo ra các sự kiện được biểu diễn dưới dạng enum. Tất nhiên, cho hiệu quả tốt nhất, nhà sản xuất này là zero-sao chép, tức là nó sẽ trả về tham chiếu đến bộ đệm nội bộ của mình:Tại sao đặc điểm Mượn yêu cầu loại vay phải là tham chiếu?
enum Variant<'a> {
Nothing,
SomeInt(u64),
SomeBytes(&'a [u8])
}
impl Producer {
fn next(&'a mut self) -> Variant<'a> { ... }
}
Đây là hoàn toàn tốt đẹp cho người tiêu dùng mà không cần lookahead hay dấu vết quay, nhưng đôi khi có một cần lưu một số chuỗi sự kiện. Vì vậy, loại Variant
của chúng tôi sẽ trở thành một generic:
enum Variant<BytesT> {
Nothing,
SomeInt(u64),
SomeBytes(BytesT)
}
type OwnedVariant = Variant<Vec<u8>>;
type BorrowedVariant<'a> = Variant<&'a [u8]>;
Ở đây, chúng tôi kết thúc với hai loại với "chủ sở hữu tài liệu tham khảo" mối quan hệ, mà là tương tự như cặp Vec<T>
- &[T]
, String
-&str
. Documents đề nghị đặc điểm BUILTIN Borrow
và ToOwned
cung cấp chỉ là những gì được yêu cầu ngoại trừ một sắc thái tinh tế:
trait Borrow<Borrowed: ?Sized> {
fn borrow(&self) -> &Borrowed;
// this: -----------^
}
pub trait ToOwned {
type Owned: Borrow<Self>;
fn to_owned(&self) -> Self::Owned;
}
Kết quả borrow
là cần thiết để trở thành một tài liệu tham khảo một cái gì đó, mà BorrowedVariant<'a>
rõ ràng là không. Loại bỏ yêu cầu này giải quyết vấn đề này (ở đây, tên được bắt đầu với alt để nhấn mạnh một thực tế đây là một giao diện thay thế):
trait AltBorrow<'a, AltBorrowed> {
fn alt_borrow(&'a self) -> AltBorrowed;
}
trait AltToOwned<'a> {
type AltOwned: AltBorrow<'a, Self>;
fn alt_to_owned(&'a self) -> Self::AltOwned;
}
đặc điểm này sau đó có thể được thực hiện với nhiều loại tiêu chuẩn, ví dụ Vec
:
impl<'a, T> AltBorrow<'a, &'a [T]> for Vec<T> {
fn alt_borrow(&'a self) -> &'a [T] {
self.as_slice()
}
}
impl<'a, T> AltToOwned<'a> for &'a [T]
where T: Clone
{
type AltOwned = Vec<T>;
fn alt_to_owned(&'a self) -> Vec<T> {
self.to_vec()
}
}
Cũng như cho Variant
enum trong câu hỏi:
impl<'a> AltBorrow<'a, BorrowedVariant<'a>> for OwnedVariant {
fn alt_borrow(&'a self) -> BorrowedVariant<'a> {
match self {
&Variant::Nothing => Variant::Nothing,
&Variant::SomeInt(value) => Variant::SomeInt(value),
&Variant::SomeBytes(ref value) => Variant::SomeBytes(value.alt_borrow()),
}
}
}
impl<'a> AltToOwned<'a> for BorrowedVariant<'a> {
type AltOwned = OwnedVariant;
fn alt_to_owned(&'a self) -> OwnedVariant {
match self {
&Variant::Nothing => Variant::Nothing,
&Variant::SomeInt(value) => Variant::SomeInt(value),
&Variant::SomeBytes(value) => Variant::SomeBytes(value.alt_to_owned()),
}
}
}
Cuối cùng, câu hỏi:
- Tôi lợi dụng bản gốc
Borrow
/ToOwned
khái niệm? Tôi có nên sử dụng cái gì khác để đạt được điều này? - Nếu không, thì lý do tại sao giao diện ít chung chung hiện tại từ
std::borrow
có thể đã được ưu tiên hơn?