我用rust写区块链——序列化与反序列化

讨论 我不是赌鬼
Lv5 宗师级炼丹师
发布在 综合   1565   0
讨论 我不是赌鬼   1565   0

    undefined
    看了几天rust教程,颇感无聊,于是上B上,看视频学怎么《用rust写区块链》。 没错,刚会hello world就开始做“几万个亿”的项目了。看完视频几集视频,不禁有感而发:人生苦短,我用python。 由于自己基础薄弱,视频中讲的也不是特别适合小白,所以我自己找了资料作为对课程的补充,可能有哆嗦或不对的地方请见谅。

    undefined

    没办法,自己约得炮,哭着也要打完。今天分析区块链的一个基本模块:序列化与反序列化

    首先,和python一样,需要导入库,不过,这个库需要写在Cargo.toml的[dependence]中。使用包管理器cargo进行编译时,若发现库没有安装,则会自动进行安装。

    
    [package]
    name = "utils"
    version = "0.1.0"
    authors = ["大写的牛逼"]
    edition = "2018"
    
    [dependencies]
    serde = {version = "1.0.114" ,features = ["derive"]}
    bincode = "1.3.1"
    

    cretes.io中,可以搜索到各种库,并提示你怎么将它加入依赖中,还有API,简单示例等等,简直不能再贴心了,例如bincode

    undefined

    为啥bincode = "1.3.1"简简单单,但导入serde却这么复杂呢,features = ["derive"]是什么鬼, 《可派生的trait》 指出

    derive 属性会在使用 derive 语法标记的类型上生成对应 trait 的默认实现的代码。

    在我看来,rust的derive与python的语法糖类似,在一个对象上标记一下,那么这个对象 就有了一个新的功能(特征)。而在[dependencies]中,serde的写法可参考serde文档

    Serde provides a derive macro to generate implementations of the Serialize and Deserialize traits for data structures defined in your crate, allowing them to be represented conveniently in all of Serde's data formats.

    You only need to set this up if your code is using #[derive(Serialize, Deserialize)]

    Add serde = { version = "1.0", features = ["derive"] } as a dependency in Cargo.toml.

    以上这段说明解释了serde在依赖中的写法,也解释了coder.rs中的结构体的derive属性

    #[derive(Serialize,Deserialize,PartialEq,Eq,Debug)]
    struct Point {
        x:i32,
        y:i32,
    }

    接着我们一段一段地分析coder.rs中的其他代码

    //对某对象进行序列化与反序列化
    use bincode;
    //使对象可以被序列化与反序列化
    use serde::{Deserialize,Serialize};
    

    上面用了两个use,和python的import类似,如果不把bincode等写在toml中,需要提供绝对或相对路径。拍一拍自己聪明的小脑袋,各种语言总是不会差太多, 接着是一个序列化函数,这时候,不得又在次感叹人生苦短,我学python,看了3天教程,我 硬是看懵了,需要对着函数反复翻文档才能理解。

    
    pub fn my_serialize<T:?Sized>(value:&T) ->Vec<u8>
        where T: Serialize,
    {
        let seialized =bincode::serialize(value).unwrap();
        seialized
    }
    

    其中,fn是创建一个函数的意思, pub可以加在函数前,声明该函数是公有的。显然,my_serialize 是函数名,(value:&T)表示输入的值是对一个泛型的借用,接着是->Vec, 无疑,是返回里面全是u8的向量。 where也好理解,给函数的返回加了一个条件,该条件为泛型T是可以被序列化的。具体可以 看《where clauses》

    A bound can also be expressed using a where clause immediately before the opening {, rather than at the type's first mention. Additionally, where clauses can apply bounds to arbitrary types, rather than just to type parameters.

    个人认为此处令狐一冲使用了where是因为模仿文档中例程的原因,例程中强调了T是可序列化的, 换一种传统的写法也是可以编译的。

    pub fn my_serialize<T:?Sized+Serialize>(value:&T) ->Vec<u8>
    {
        let seialized =bincode::serialize(value).unwrap();
        seialized
    }

    那么挤在中间的<T:?Size>是啥东西呢,引用《泛函数据类型》 中说的:

    在函数签名中使用一个类型参数时,必须在使用它之前就声明它。为了定义泛型版本的my_serialize函数,类型参数声明位于函数名称与参数列表中间的尖括号 <> 中.

    这里比较难理解,尤其对于像我这种只会写python又不懂编译原理的菜鸡来说。

    没办法,不懂就要找资料,我找了B站令狐一冲的课程《在函数与结构体中使用泛型》, 里面提到

    <>是对泛型的约束,(在后面的课程中又具体的讲到这是[trait_bound写法](https://www.bilibili.com/video/BV1FJ411Y71o?p=6)

    那么<T:?Size>从字面意思上看代表的约束就是泛型没有长度的限制,emmm,好像有点不对劲。 理智告诉我事情没这么简单,于是我又搜了一下,某乎上的《类型的大小》对?Sized有很清晰的解释

    Rust中有一个重要的 trait Sized,可以用于区分一个类型是不是 DST。所有的 DST 类型都不满足 Sized 约束。我们可以在泛型约束中使用 Sized、!Sized、?Sized 三种写法。其中 T:Sized 代表类型必须是编译期确定大小的,T:!Sized 代表类型必须是编译期不确定大小的,T:?Sized 代表以上两种情况都可以。在泛型代码中,泛型类型参数默认携带了 Sized 约束,因为这是最普遍最常见的情况。如果我们希望这个泛型参数也可以支持 DST 类型,那么就应该为它专门加上 ?Sized 约束

    最后,比较难以理解的地方是unwrap()......emmm,下次再见

    版权声明:作者保留权利,不代表意本站立场。如需转载请联系本站以及作者。

    参与讨论

    回复《 我用rust写区块链——序列化与反序列化

    EditorJs 编辑器

    沙发,很寂寞~
    反馈
    to-top--btn