腐蚀rust哪个键可以拆除_用Rust写脚本语言(十六):Rust代码就是一层套一层套一层套一层的大洋葱...

Cowsay:用Rust写脚本语言(零):目录​zhuanlan.zhihu.com
91d2549f82d33b3b59b0cdbad6ba2296.png

对不起各位,想法中预告的「大一统」至少还要再等一篇文章了。

我最大的错误就是,在预估项目进度的时候,总是习惯性的把Rust当成Python去考虑任务量。

实际上,Rust还是更像C++一点。那些让项目无比扎实的boilerplate,无法省略也不应该省略。这是一件麻烦事,好的那种。当然了,Rust提供了比C++强大得多的宏系统来尽量精简重复代码,只是我不太喜欢用而已。

更严重的问题是,Rust中的boilerplate还有可观的一部分是由于生命周期的原因才引入的。这些代码我在写C++的时候也没遇到过,所以真正遇到之前根本无法想到,居然会有这么这么这么大的一坨……


今天不放项目地址了,现在的项目里几乎所有的模块都被暂时注释掉了,实在没眼看。新添加的SharedMemory的用法在后面的文章里再详细讲,这篇文章的重点是吐槽

impl<'a, O> RemoteObjectGuard<'a, O> {
    pub fn read(&self) -> ReadRemoteObject<O> {
        let read = ReadRemoteObject {
            guard: self
                .guard
                .objects
                .get(&self.object_id)
                .expect("segfault")
                .object
                .read()
                .unwrap(),
        };
        read
    }

    pub fn write(&self) -> WriteRemoteObject<O> {
        let write = WriteRemoteObject {
            guard: self
                .guard
                .objects
                .get(&self.object_id)
                .expect("segfault")
                .object
                .write()
                .unwrap(),
        };
        write
    }
}

恍惚间我真的以为自己在写JavaScript。

首先我需要一个散列表,表本身可能被多个用户插入/删除元素,所以需要Arc<RwLock<...>>。表本身放进锁还不够,键生成器也要放进去,于是我们有

pub struct SharedMemory<O> {
    internal: Arc<RwLock<SharedMemoryPriv<O>>>,
}
struct SharedMemoryPriv<O> {
    objects: HashMap<usize, CountedObject<O>>,
    object_id: Inc,
}

(哦对了,这个XXPriv还埋了一个坑,谁会知道priv居然也是Rust的保留字……)

那么CountedObject又是什么东西?在不改变散列表本身的情况下,写一个对象不应该阻塞对另一个对象的读写,所以每一个对象都应该存入一个单独的锁中

struct CountedObject<O> {
    object: RwLock<O>,
    count: usize,
}

当有人想要访问对象时,count就会增加1;用户不再需要它了,count就会减去1。通过类似于引用计数的方式决定一个对象是否需要存留在散列表中。说是「类似于」是因为对象之间不会互相引用,所有的引用计数来自于外部,因此没有循环引用的问题。

也许你猜到了,「用户不再需要它了」是通过RAII语义,实现 Drop来表达的。多年以后,我成为了自己最讨厌的人……

也就是说,对一个对象的释放持有操作有可能会影响散列表(没人引用了的对象要从表中删除),所以交给用户的对象代理不能仅仅包含对对象本身的控制权,还要能操作整个表

pub struct RemoteObject<O> {
    internal: Arc<RwLock<SharedMemoryPriv<O>>>,
    object_id: usize,
}

既然这里出现了RwLock<...>, 有了之前文章中的惨痛教训,我自然会意识到,RwLockReadGuard<...>是不可能省略的

pub struct RemoteObjectGuard<'a, O> {
    guard: RwLockReadGuard<'a, SharedMemoryPriv<O>>,
    object_id: usize,
}

然后呢?对于整个表的RwLockReadGuard都出现了,对于单个对象的还会远吗?

pub struct ReadRemoteObject<'a, O> {
    guard: RwLockReadGuard<'a, O>,
}

和表不同的是,单个对象还可以被可变借用

pub struct WriteRemoteObject<'a, O> {
    guard: RwLockWriteGuard<'a, O>,
}

七个,整整七个结构体,配上方法整整要写170行,其中就包括最上面的那两个方法,用于从整个表的RwLockReadGuard中提取对一个对象的guard。

这事告诉我们,Rust和Lock和RAII是真的真的不搭调。如果有机会,我要在Shattuck中试试看,有没有不这么反人类的写法。

哎,真是一门「素雅」的语言啊……
Cowsay:用Rust写脚本语言(零):目录​zhuanlan.zhihu.com
91d2549f82d33b3b59b0cdbad6ba2296.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值