怎样优雅地增删查改(三):业务用户的增删无需重写查改

Rust 中的 runtime 到底是咋回事, 为了彻底搞懂它, 我在尽量不借助第三方 crate 的情况下实现了一个玩具 runtime, 之所以说是玩具,因为它没有复杂的调度算法(只有一个全局 task queue)

代码除了 mpmc(multi-producer, multi-consumer) 使用第三方 crate crossbeam 之外, 其余代码一律手撸

可以这么玩

fn main() {
    let toy = Toy::new();

    for i in 1..=20 {
        toy.spawn(async move {
            let ret = FakeIO::new(Duration::from_secs(i)).await;
            println!("{:?}: {:?}", thread::current().id(), ret);
        })
    }

    toy.run(4); // 4 threads
}

其中 FakeIO 也是足够单纯

pub struct FakeIO {
    finished: Arc<AtomicBool>,
    duration: Duration,
}

impl Future for FakeIO {
    type Output = Duration;

    fn poll(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        if self.finished.load(Ordering::Acquire) {
            return Poll::Ready(self.duration);
        }

        let finished = self.finished.clone();
        let waker = cx.waker().clone();
        let duration = self.duration;

        thread::spawn(move || {
            thread::sleep(duration);

            finished.store(true, Ordering::Release);

            waker.wake();
        });

        Poll::Pending
    }
}

数据结构

数据结构就下面几个(参考了 tokio 的设计)

struct Task {
    raw: RawTask,
}

unsafe impl Send for Task {}
unsafe impl Sync for Task {}

struct RawTask {
    ptr: NonNull<Header>, // pointer to Cell<T> where T: Future
}

struct Header {
    // todo: maybe replace the Mutex<State> with AtomicUsize
    state: Mutex<State>,
    vtable: &'static Vtable,
    sender: crossbeam::channel::Sender<Task>,
}

#[derive(Default)]
struct State {
    running: bool,
    notified: bool,
    completed: bool,
}

/// #[repr(C)] make sure `*mut Cell<T>` can cast to valid `*mut Header`, and backwards. 
/// In the default situation, the data layout may not be the same as the order in which the fields are specified in the declaration of the type
/// 默认情况下 Rust 的数据布局不一定会按照 field 的声明顺序排列
/// [The Default Representation](https://doc.rust-lang.org/reference/type-layout.html?#the-default-representation)
///
/// [playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=39ac84782d121970598b91201b168f82)
/// 
/// you can easilly view the data layout with this crate https://github.com/hangj/layout-rs
#[repr(C)]
struct Cell<T: Future> {
    header: Header,
    future: T,
    output: Option<T::Output>,
}

struct Vtable {
    poll_task: unsafe fn(NonNull<Header>),
    clone_task: unsafe fn(NonNull<Header>) -> NonNull<Header>,
    drop_task: unsafe fn(NonNull<Header>),
}

其中值得注意的是:

  • RawTask 内的 ptr 实际上指向的是 NonNull<Cell<T: Future>>
  • Cell<T: Future> 被标记了 #repr(C), 原因已在注释中说明
  • vtable 的设计参考了 Waker 中的 vtable, 相当于利用泛型函数保存了类型信息, 便于后面从裸指针恢复到原始类型

Have fun!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Android Studio中,SQLite是一个常用的本地数据库,用于存储应用的数据。使用SQLite进行增删查改(CRUD)操作,可以通过Android的Java或Kotlin API来实现。以下是一些基本步骤: 1. **创建数据库**: - 首先,在`res`目录下创建`database`文件夹,然后在其中创建一个`.db`文件(例如`app.db`),这是SQLite文件的实际位置。 - 在AndroidManifest.xml中添加权限: ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ``` 2. **连接数据库**: - 使用`SQLiteOpenHelper`类来管理数据库版本和事务。创建一个继承自它的子类,并重写`onCreate()`和`onUpgrade()`方法。 ```java public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "app.db"; private static final int DATABASE_VERSION = 1; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } // ... } ``` 3. **CRUD操作**: - **插入数据** (Insert): - 创建SQL INSERT语句并调用`insert()`方法。 ```java ContentValues contentValues = new ContentValues(); contentValues.put("column_name", "value"); dbHelper.getWritableDatabase().insert("table_name", null, contentValues); ``` - **查询数据** (Read): - 使用`query()`方法执行SQL SELECT查询。 ```java Cursor cursor = dbHelper.rawQuery("SELECT * FROM table_name WHERE column_name = ?", new String[]{"value"}); while (cursor.moveToNext()) { // 获取结果 } cursor.close(); ``` - **更新数据** (Update): - 构造SQL UPDATE语句,并使用`update()`方法。 ```java int rowsAffected = dbHelper.getWritableDatabase().update("table_name", contentValues, "column_name = ?", new String[]{"value"}); ``` - **删除数据** (Delete): - 构造SQL DELETE语句,然后调用`delete()`方法。 ```java int deletedRows = dbHelper.getWritableDatabase().delete("table_name", "column_name = ?", new String[]{"value"}); ``` 4. **事务处理**: - 如果需要确保一组操作要么全部成功要么全部失败,可以使用`beginTransaction()`、`endTransaction()`以及`setTransactionSuccessful()`或`rollback()`。 5. **关闭连接**: - 在完成所有操作后,记得关闭`Cursor`和数据库连接。 ```java cursor.close(); dbHelper.close(); ``` **相关问题--:** 1. Android Studio中的SQLiteOpenHelper类有何作用? 2. 如何在Android Studio中执行带有参数的SQL查询? 3. 在Android中,如何正确处理数据库操作的异常?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值