首页 > 其他分享 >QRust(二)数据类型

QRust(二)数据类型

时间:2024-11-11 13:57:26浏览次数:1  
标签:QRust QHash struct list 数据类型 upack HashMap pack

QRust支持的数据类型可分为两类:基本类型、集合类型。这些数据类型可作为函数参数、返回值或struct的字段,在Qt和Rust之间传递。

基本类型

Rust端 Qt端
bool bool
i8 qint8
i16 qint16
i32 qint32
i64 qint64
u8 quint8
u16 quint16
u32 quint32
u64 quint64
f32 float
f64 double
String QString
T struct T struct

集合类型

Rust端 Qt端
Vec<bool> QList<bool>
Vec<i8> QList<qint8>
Vec<i16> QList<qint16>
Vec<i32> QList<qint32>
Vec<i64> QList<qint64>
Vec<u8> QList<quint8>
Vec<u16> QList<quint16>
Vec<u32> QList<quint32>
Vec<u64> QList<quint64>
Vec<f32> QList<float>
Vec<f64> QList<double>
Vec<String> QList<QString>
Vec<T struct> QList<T struct>
HashMap<i32, bool> QHash<qint32, bool>
HashMap<i32, i8> QHash<qint32, qint8>
HashMap<i32, i16> QHash<qint32, qint16>
HashMap<i32, i32> QHash<qint32, qint32>
HashMap<i32, i64> QHash<qint32, qint64>
HashMap<i32, u8> QHash<qint32, quint8>
HashMap<i32, u16> QHash<qint32, quint16>
HashMap<i32, u32> QHash<qint32, quint32>
HashMap<i32, u64> QHash<qint32, quint64>
HashMap<i32, f32> QHash<qint32, float>
HashMap<i32, f64> QHash<qint32, double>
HashMap<i32, String> QHash<qint32, String>
HashMap<i32, T struct> QHash<qint32, T struct>
HashMap<String, bool> QHash<QString, bool>
HashMap<String, i8> QHash<QString, qint8>
HashMap<String, i16> QHash<QString, qint16>
HashMap<String, i32> QHash<QString, qint32>
HashMap<String, i64> QHash<QString, qint64>
HashMap<String, u8> QHash<QString, quint8>
HashMap<String, u16> QHash<QString, quint16>
HashMap<String, u32> QHash<QString, quint32>
HashMap<String, u64> QHash<QString, quint64>
HashMap<String, f32> QHash<QString, float>
HashMap<String, f64> QHash<QString, double>
HashMap<String, String> QHash<QString, QString>
HashMap<String, T struct> QHash<QString, T struct>

注意上面表格中以q开始的通常是一些C++类型的别名,比如qint32就是int。在使用QRust编程时变量定义为qint32还是int是没有区别的,下面列出了这些别名的对应。

typedef C++原类型
qint8 signed char
qint16 signed short
qint32 signed int
qint64 long long int
quint8 unsigned char
quint16 unsigned short
quint32 unsigned int
quint64 unsigned long long int

数据包结构

以上类型的数据在Qt和Rust之间传递时被封装为一种二进制包结构,基本类型的包结构如下:

基本数据类型包结构以一个字节的tag标记开始,tag的数值表示这是哪种类型,后面的值部分根据类型不同占用字节长度也有区分,比如i8和u8占用1个字节,u16和i16占用两个字节。比较特殊的是string类型,在tag后紧跟4个字节描述字符串的长度,在长度单元后是字符串的值(utf-8字节向量,没有’\0’结尾)。

集合类型的包结构稍显复杂一些,但不难理解。

list包结构:

list包的tag根据其包含的数据类型不同而有变化,范围50~99。tag后跟4字节长度单元,描述list包体的长度。包体部分是一个接一个的元素,元素的结构和基本数据包结构一样。

以int为key的Hash包结构:

hash包的tag根据其包含的数据类型变化,范围100~149,和list一样tag后跟4字节长度单元。包体中每个元素由两部分组成,因为key是int类型所以结构和基础包结构中的i32相同,值部分也是可参照基础包结构的描述。

以字符串为key的Hash包结构:

以字符串为key的tag取值范围150~199,和以int为key的hash包结构基本相同,只是元素key有变化。

struct类型:

QRust支持自定义的struct类型,struct在应用场景中可以等同为对象,支持struct的自动化(也可能称之为半自动化)转换是QRust的靓点之一。

使用Qrust进行struct数据类型在Qt和Rust之间传递时,有以下注意点:

1)字段名称、数量双方必须一致,struct名称可以不一样。

2)Rust端需要对struct加上序列化和反序列化的宏标记,例如:

[derive(Serialize, Deserialize, Clone, Debug)]
pub struct A {
    a: bool,
    v: Vec,
}

3)Qt端需要对struct进行QMetaObject的改造,例如:

struct A{
  Q_GADGET
  Q_PROPERTY(bool a MEMBER a);
  Q_PROPERTY(QList v MEMBER v);
public:
  bool a;
  QList v;
};

在Rust端必须给struct添加Serialize和Deserialize宏,在Qt端需要对struct进行以下扩展:

  • 第一需要添加 Q_GADGET 宏标志,来支持Qt的元对象编程。
  • 第二为每个字段添加 Q_PROPERTY 宏,格式: Q_PROPERTY(类型 字段名 MEMBER 字段名),Q_PROPERTY 宏支持struct的字段遍历、读写、以及类型推导。
  • 第三在字段前添加 public:标志,因为Q_PROPERTY 宏执行以 private: 结束,将导致所有字段变为私有的,添加 public: 将强制改回来。

struct的包结构是所有类型中最复杂的,但也不难理解:

struct的tag标志是24(10进制),tag后的一个字节描述struct名称的长度,后面跟struct名称字符串向量。名称后的一个字节描述字段的数量(这点限制了字段最多255个),再后面4个字节描述包体的长度,包体部分是一个一个的字段。字段结构分为两个部分,字段名和字段值。字段名符合基本类型String的定义,字段值可参考基本类型或集合类型的定义。

注意struct字段并没有全部支持基本类型和集合类型,需要去除这几个:

  • struct
  • Vec<struct>
  • HashMap<i32, struct>
  • HashMap<String, struct>

类型不足的原因和解决方法

struct的字段不能再定义为另一个struct类型,既struct不能嵌套,例如你不能在QRust中使用如下的struct定义:

struct A{
struct B b;
}

同样的原因在集合类型中也不能嵌套其他集合,你不能定义这样的变量:

QList<QHash<int, bool>> a;

集合类型和struct都属于复杂类型,QRust不支持复杂类型嵌套的原因和序列化和反序列化技术有关,序列化技术在Rust端使用了规范框架库serde,在Qt端对struct的处理使用了QMetaObject,这两种技术都不支持嵌套或不完全支持。

对于Rust和Qt这种静态语言在序列化处理过程中离不开模板和宏,例如在struct的序列化过程中进行类型推导,编译预处理时就可能生成大量代码而增加源代码的长度,如果允许复杂类型的嵌套,代码长度可能会指数级增加导致出现问题。有关C++模板和Rust宏的编译预处理比较复杂,这里不展开讨论,有兴趣可浏览相关的书籍资料。

但struct嵌套是经常遇到的场景,比如下面的struct结构:

struct User{
  qint32  id;
  QString name;
  struct Address address; 
};

在用户对象中包含地址对象是自然而然地,如果不支持嵌套怎么来解决这个问题呢?QRust的解决办法是扁平化,将User和Address分成两个参数传递,函数定义可做修改:

add_user(user);  //原定义user中包含address

改为:

add_user(user, address);  //扁平化的

函数入参比较容易进行扁平化,如果从数据库查询,即函数返回值怎样处理呢,能同时返回user和address吗?答案是可以,QRust针对性的做了扩展,可以同时返回多个返回值。

Rust端的函数定义,返回tuple结构可包含多个返回值:

pub fn get_user(user_id: i32) -> (User, Address)

反序列化时也可对多个返回值进行处理:

let (user, address) = get_user(user_id); 
let mut pack = Vec::new();
pack.extend(ser::to_pack(&user)?);  //序列化第一个返回值
pack.extend(ser::to_pack(&address)?);   //序列化第二个返回值
let pack_multi = ser::to_pack_multi(pack);  //两个返回值组包在一起
Ok(Some(pack_multi))

在OnTheSSH软件中,经常使用这种多返回值的方式,例如系统监控要同时获得CPU、内存、磁盘、网络、端口等多种结构信息。

这个问题再扩展一些,比如获得全部用户时,扁平化可以这样处理:

pub fn get_all_users() -> (Vec<User>, Vec<Address>)
pub fn get_all_users() -> (Vec<User>, HashMap<i32, Address>)

第一种方式需要在Address中定义一个user_id的字段,来关联地址是属于哪一个用户的,第二种则直接用key进行关联。这也是在QRust的Hash类型中为什么会同时存在int和string两种类型的key,因为int和string在数据库中最常用作主键,使用频率都很高。

QRust对函数参数和多返回值的最大数量,限制在255个。

空和异常

在业务系统中空和异常是经常遇到的特殊结果,比如get_user(id)时用户已被删除,或者发送命令而网络不可达时。在OnTheSSH软件中是利用多返回值来处理空和异常的,第一个返回值是一个特殊结构:

struct RetState
{
    bool    state;          
    qint32  err_code;       
};

字段state表示函数执行的状态,如果为真表示函数执行成功,你再从第二个返回值开始获得函数的结果,反之如果为假,就不必获取后续的函数结果了,这时应该查看err_code字段是哪种错误的编码。

序列化和反序列化函数

使用serde框架让Rust有很好的类型推导能力,所以序列化和反序列化时有统一from_pack和to_pack函数。Qt端目前还做不到,每种类型都需要对应独立的函数,下表列出了所有的序列化和反序列化对应关系:

类型 序列化函数 反序列化函数
bool pack_bool upack_bool
qint8 pack_i8 upack_i8
qint16 pack_i16 upack_i16
qint32 pack_i32 upack_i32
qint64 pack_i64 upack_i64
quint8 pack_u8 upack_u8
quint16 pack_u16 upack_u16
quint32 pack_u32 upack_u32
quint64 pack_u64 upack_u64
float pack_f32 upack_f32
double pack_f64 upack_f64
QString pack_str upack_str
struct pack_struct upack_struct
QList<bool> pcak_list_bool upcak_list_bool
QList<qint8> pcak_list_i8 upcak_list_i8
QList<qint16> pcak_list_i16 upcak_list_i16
QList<qint32> pcak_list_i32 upcak_list_i32
QList<qint64> pcak_list_i64 upcak_list_i64
QList<quint8> pcak_list_u8 upcak_list_u8
QList<quint16> pcak_list_u16 upcak_list_u16
QList<quint32> pcak_list_u32 upcak_list_u32
QList<quint64> pcak_list_u64 upcak_list_u64
QList<float> pcak_list_f32 upcak_list_f32
QList<double> pcak_list_f64 upcak_list_f64
QList<QString> pcak_list_str upcak_list_str
QList<T struct> pcak_list_struct upcak_list_struct
QHash<qint32, bool> pack_hi_bool upack_hi_bool
QHash<qint32, qint8> pack_hi_i8 upack_hi_i8
QHash<qint32, qint16> pack_hi_i16 upack_hi_i16
QHash<qint32, qint32> pack_hi_i32 upack_hi_i32
QHash<qint32, qint64> pack_hi_i64 upack_hi_i64
QHash<qint32, quint8> pack_hi_u8 upack_hi_u8
QHash<qint32, quint16> pack_hi_u16 upack_hi_u16
QHash<qint32, quint32> pack_hi_u32 upack_hi_u32
QHash<qint32, quint64> pack_hi_u64 upack_hi_u64
QHash<qint32, float> pack_hi_f32 upack_hi_f32
QHash<qint32, double> pack_hi_f64 upack_hi_f64
QHash<qint32, QString> pack_hi_str upack_hi_str
QHash<qint32, T struct> pack_hi_struct upack_hi_struct
QHash<QString, bool> pack_hs_bool upack_hs_bool
QHash<QString, qint8> pack_hs_i8 upack_hs_i8
QHash<QString, qint16> pack_hs_i16 upack_hs_i16
QHash<QString, qint32> pack_hs_i32 upack_hs_i32
QHash<QString, qint64> pack_hs_i64 upack_hs_i64
QHash<QString, quint8> pack_hs_u8 upack_hs_u8
QHash<QString, quint16> pack_hs_u16 upack_hs_u16
QHash<QString, quint32> pack_hs_u32 upack_hs_u32
QHash<QString, quint64> pack_hs_u64 upack_hs_u64
QHash<QString, float> pack_hs_f32 upack_hs_f32
QHash<QString, double> pack_hs_f64 upack_hs_f64
QHash<QString, QString> pack_hs_str upack_hs_str
QHash<QString, T struct> pack_hs_struct upack_hs_struct

标签:QRust,QHash,struct,list,数据类型,upack,HashMap,pack
From: https://www.cnblogs.com/dyf029/p/18539554

相关文章

  • QRust(一) 简介
    QRust是一个开源组件,是Qt和Rust两种语言的混合编程中间件,是Qt调用Rust函数的支持技术。QRust来源于工具软件OnTheSSH,OnTheSSH软件由Qt和Rust两种语言共同构建,Rust实现了SSH通讯底层协议,Qt搭建程序界面,Qt调用Rust的技术需求催生出了QRust。一个使用QRust的例子:Rust端:fninvo......
  • 第 5 章 - Go 语言 数据类型
    在Go语言中,数据类型是用来声明变量和函数的特定类型的数据。Go是一种静态类型的语言,这意味着所有变量的类型在编译时都必须已知。Go语言支持多种数据类型,可以大致分为基本数据类型和复合数据类型。基本数据类型布尔型(bool)只有两个值:true和false。整型(int,......
  • C++函数返回多种数据类型
    返回复合数据的结构体定义一个结构体Result,它包含一个整数、一个数组(使用std::vector)和一个矩阵(使用std::vector<std::vector>)。然后实现一个函数来填充这些数据并返回。示例代码:#include<iostream>#include<vector>#include<string>structResult{intn......
  • C++基础学习2-数据类型
    ////数据类型:////计算机语言-写程序-解决生活中的问题////必须有能力来描述生活中的问题////购物商城-上架商品,价格-15.6元-小数////年龄50岁-整数////C语言-浮点数(小数点)////-整型//////a////'a'-字符a////intmain()//{// //char=字符类型// charch='a';......
  • 1.Kotlin-基本数据类型及运算
    一.Kotlin基本数据类型基本数据类型包括:Byte,Short,Int,Long,Float,Double数据类型推断:Kotlin中的数据类型全部以val进行声明,编译器会自动推断数据类型当然也可以在变量名后加:数据类型的形式,显示指明数据类型valbyteNumber:Byte=127;//Byte1.整数类型类......
  • c++-有关输出、信息输入、趣味输入应用、运算符、变量、浮点数数据类型的基础知识
    C++是一种功能强大且广泛使用的编程语言,它可以用于开发各种类型的应用程序。在这篇文章中,我们将介绍C++程序的输出、信息输入、趣味输入应用、运算符、变量和浮点数数据类型的基础知识。目录输出信息输入趣味输入应用运算符变量浮点数数据类型题目题目1:解答1:题目2:......
  • C语言数据结构之二叉树(BINARY TREE)的多种数据类型存贮
    C语言数据结构之二叉树(BINARYTREE)的多种数据类型存贮用无类型指针(void*)来做为基本数据类型来存贮数据,将其他数据类型强制转化为无类型指针,从而达到目标!!!输出函数指针BTFunc比较函数指针BTCmpFunc返回值为整型值1、-1、0,表示大于、小于、相等代码如下:/*filename:btr......
  • python基础——04数据类型(元组,集合,字典)
    一、元组(tuple)1.1什么是元组元组和列表相似,但元组的元素放在()里面。t=(1,2,3,4,5)print(type(t))#<class'tuple'>t1=('hello')#<class'str'>这不是元组t2=('hello',)#<class'tuple'>print(type(t1),type(t2)......
  • C++ 的“百变魔法”:搞懂基本数据类型和变量
    编程世界里,数据就像材料,而基本数据类型就决定了这些材料能做什么。每种数据类型都有它自己的“特长”,我们可以用它们来处理不同的信息。今天,我们就来看看C++里最常见的几种基本数据类型:int,char,float,double,bool,以及如何用变量来存储这些数据。什么是数据类型?简单......
  • 1.python的基本语法和简单数据类型
    1.1语法特点1.1.1注释语句单行注释在所需注释内容前加'#'号#我是一个注释多行注释'''(单引号/或双引号)注释代码''''''我是代码我是代码我是代码我是代码'''1.2.1缩进先看代码if<我是条件1>:<我是代码><我是代码>else:<我是......