[英]How can I implement Deref for a struct that holds an Rc<Refcell<Trait>>?
[英]How can I use polymorphism with the Deref trait to have a a single object that can be represented by either a Transaction or Connection?
我正在将rustqlite库用于 SQLite 数据库(操场)
use std::ops::Deref;
pub struct Connection {
}
impl Connection {
pub fn transaction(&mut self) -> Transaction {
Transaction::new(self)
}
}
pub struct Transaction<'conn> {
conn: &'conn Connection
}
impl Transaction<'_> {
pub fn new(conn: &mut Connection) -> Transaction {
Transaction{ conn }
}
pub fn commit(mut self) -> Result<(), ()> {
Ok(())
}
}
impl Deref for Transaction<'_> {
type Target = Connection;
#[inline]
fn deref(&self) -> &Connection {
self.conn
}
}
通过此实现, Transaction
object 将获得Connection
object 的所有权。 同时,它还实现了Deref
trait,因此我们可以像从Connection
结构中一样调用Transaction
结构中的所有方法。
实现细节在这里
从我的应用程序代码中,我想要一个可以由Transaction
或Connection
表示的 object 。 这是必要的,因为逻辑有一个标志来决定是否使用事务。 有一个强制转换将Transaction
object 视为Connection
object:
let conn = create_connection(); // Connection
let tx = conn.transaction(); // Transaction
let conn: &Transaction = &tx; // cast back to Connection type from the Transaction type
但是,我不知道如何根据条件从应用程序 POV 安排此代码。 这是我的伪代码:
pub fn execute(is_tx: bool) {
// conn will have Connection type
let conn = match is_tx {
true => &create_connection(),
false => {
let x = create_connection().transaction();
let t: &Connection = &x;
t
}
};
// do other things with conn object
}
pub fn create_connection() -> Connection {
Connection{}
}
但是,会出现错误
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:36:21
|
36 | let x = create_connection().transaction();
| ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
37 | let t: &Connection = &x;
| -- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error[E0597]: `x` does not live long enough
--> src/lib.rs:37:34
|
37 | let t: &Connection = &x;
| ^^ borrowed value does not live long enough
38 | t
| - borrow later used here
39 | }
| - `x` dropped here while still borrowed
我理解这个错误,但我尝试了几个解决方法都没有成功,主要是因为Transaction
结构获得了Connection
结构的所有权。 我怎样才能解决这个问题?
免责声明:我没有尝试过这段代码。 不过这里只是为了让大家大致了解一下go in的方向。
首先,Rust 中的局部变量(在堆栈上)必须是固定大小的。 这是您面临的问题之一。 Transaction 和 Connection 的大小不同。 因此,如果没有一些技巧,您就无法在堆栈上实现“多态性”。
执行此操作的两种方法是枚举类型和装箱(将结构放在堆上,并添加 VTable)。
我不会 go 超过拳击,因为这相对简单。
您遇到的第二个问题是Transaction
的生命周期与Connection
相关,因此任何移动Transaction
都需要您move
Connection
。
enum MyConnection<'a> {
TransactionConnection {
transaction: Transaction<'a>
},
NakedConnection{
connection: Connection
}
}
impl MyConnection<'a> {
fn commit(mut &self) -> Result<()> {
match self {
MyConnection::NakedConnection =>
Ok(()),
MyConnection::TransactionConnection { transaction } =>
transaction.commit()
}
}
}
impl<'a> Deref for MyConnection<'a>
{
type Target = Connection;
#[inline]
fn deref(&self) -> &Connection {
match self {
MyConnection::TransactionConnection { transaction } =>
transaction.conn,
MyConnection::NakedConnection { connection } =>
connection,
}
}
}
这些枚举和 Deref 将允许您持有可以访问连接的结构。
这就是您使用上述代码的方式。
pub fn execute(is_tx: bool) {
// conn will have Connection type
let mut conn = create_connection();
let conn = match is_tx {
false => {
MyConnection::NakedConnection { connection: conn }
},
true => {
let trans = conn.transaction();
MyConnection::TransactionConnection {
transaction: trans,
}
}
};
conn.do_stuff();
conn.commit();
}
请注意, create_connection
已移出匹配项。 这样一来,连接的 scope 将始终大于MyConnection
'a
scope'a。 这“解决”了第二个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.