热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EOS入门指南PART7——如何操作multi_index

上一章我们学习了对智能合约开发来说至关重要的第一步:知道了RAM、multi_index和EOS数据库各是什么以及它们之间的关系;知道了multi_index是内存数据库的入口;了

上一章我们学习了对智能合约开发来说至关重要的第一步:

  • 知道了RAM、multi_index和EOS数据库各是什么以及它们之间的关系;
  • 知道了multi_index是内存数据库的入口;
  • 了解了multi_index内部的结构长什么样子;

今天这章,主要介绍multi_index的相关操作,趁机巩固一波上一章学习到的理论知识。

摘要

上一章说到multi_index的概念——多索引容器,multi_index容器的内部结构可以类比成传统数据库里的一张表,只不过这张表只有一列,每一行都是一个struct结构体。

这一章就要向大家介绍,如何具体使用multi_index。

primary keys

还是上一章中的例子:

《EOS入门指南PART7——如何操作multi_index》

multi_index的容器(表)里每一行都是上面的struct结构体,并且都是按照主键升序排列。所以每一个multi_index中会有一个默认索引,也就是主键。如上图,就是按照主键(pkey)升序排列的。

uint64_t primary_key() const { return pkey; }

一般而言,在struct结构体中会声明一行获得主键的方法primary_key(),这里定义了主键类型为uint64_t,返回结构体中的pkey字段,即pkey这个字段就是整个结构体的主键。

自定义索引

既然叫multi_index,肯定不只可以根据主键进行索引,事实上,我们还可以自定义索引。例如可以在结构体中定义如下方法:

account_name get_customer() const {
return customer;
}

这就是我们自定义的索引。仿照之前的primary_key()可以看到,这个方法返回值的类型为account_name,返回的字段为customer。当然自定义的索引并不一定要返回结构体中的某个字段的变量,也可以将变量之间的运算结果作为索引。

这里先贴上结构体的完整表达,方便下面介绍如何使用多索引:

struct service_struct {
uint64_t pkey;
account_name customer;
Date date;
uint32_t odometer; auto primary_key() const {return pkey;}
account_name get_customer() const {return customer;} EOSLIB_SERIALIZE(service_struct,( pkey )( customer )( date )( odometer ))
}
typedef eosio::multi_index index_by
>
> customer_index;

解释一下,使用上面的方式来定义索引,eosio::multi_index<...>的参数解释如下:

  • service : multi_index容器的表名(如上图)
  • service_struct : 智能合约重定义的struct结构体名称,也可以理解成表中的一行记录;
  • indexed_by<...>

    • N(bycustomer) : 给索引起个名字 &#8211; bycustomer
    • const_mem_fun<...> :

      • account_name : 索引的类型
      • &service_struct::get_customer:通过service_struct结构体中的get_customer函数获得(索引)

通过上述表达,就可以再生成一张按customer为索引的表bycustomer(见本文第一张图)。左边是按照主键索引的原表service,右边的表就是我们按照customer的索引生成的新表(按customer从小到大进行排列),可以看到新表内的行内容和之前是一行的(见虚线指向原表),只不过按照customer字段进行了重新排列。

这里定义了customer_index类型,这样以后就可以直接用这个类型去初始化真正的multi_index表。

迭代器

上一章我们介绍过迭代器,可以把迭代器想象成一个电梯,通过在索引中上下滑动来定位数据。接着上面介绍的自定义索引comstomer_index:

account_name customer_acct = eosio::chain::string_to_name(customer_name);
auto cust_itr = customer_index.find(customer_acct);

通过上述代码,我们就可以找到bycustomer表中,customer为某个特定值的所有行(结构体)了。比如,第一张图中,如果传入的参数为&#8221;bob&#8221;,那就可以找出所有customer为bob的数据了,放入迭代器里。通过迭代器就可以逐条获取我们想要的数据信息。

得到了迭代器之后,咱们再来看看怎么使用迭代器:

while(cust_itr != service.end() && cust_itr -> customer == customer_acct) {
// code to execute
cust_itr++;
}

其中cust_itr != service.end()表示迭代器并没有走到service表的结尾,&&之后也很容易看懂,再筛选customer的值。每次小的遍历结束是,迭代器+1,表示继续访问迭代器中的下一行。

索引和迭代器如何配合工作

通过上面的介绍,大家应该就可以理清multi_index和迭代器是如何配合工作的:

i通过multi_index可以得到一张按照特定字段索引的表,再通过对索引设置一些条件,就可以筛选得到一些迭代器,再通过对迭代器的遍历,就可以访问我们想要访问的数据了。

multi_index的初始化

上文关于multi_index多与定义有关,现在终于要开始实例化multi_index了。

multi_index(uint64_t code, uint64_t scope)

在上面的初始化(实例化)的语句中,可以看到有两个参数:

  • code -拥有这张multi_index表的账户,该账户拥有对合约数据的读写权限;
  • scope &#8211; 用户账户名下的区域。可以在code下定义多个scope,把属于不同scope的表隔离开;

这里的code和scope,都是用来为表建立访问权限的。

所以要想初始化上面的customer_index,可以使用:

// customer_index 就是之前 typedef 定义的类型
// bycustomer就是新表
// _self就是当前调用方法的账户
customer_index bycustomer(_self, _self);

添加 &#8211; emplace

这里顺便说一下find,multi_index使用.find来查询,代码接上往下写:

void demo::create(const uint64_t id,
const account_name cust_acct,
const Date date,
const uint32_t odometer) {
// 找出特定值的customer的数据
// 这里的auto相当于其他语言中的var,声明变量时不指定类型
auto itr = bycustomer.find(cust_acct);
// 查询customer = cust_acct的记录并要求该记录不存在
// 因为primary_key不能重复
// 所以插数据之前先查询一下,保证不重复
eosio_assert(itr == profile.end(), "Account already exists");
// 往索引里添加记录
bycustomer.emplace(cust_acct, [&](auto& c)) {
c.pkey = id;
c.customer = cust_acct;
c.date = date;
c.odometer = odometer;
}
}

其中[&](auto& c)是c11之后一种新的lambda表达式,有兴趣的同学可以自行深入了解,这里简单介绍一下,这个表达式大概表示:

除了该函数已有的参数,其他的参数例如 id, date, odometer这些,都是在上层的作用域中通过引用的形式传入函数内。

其中auto我们之前说过,表示不限制类型,但是也为引用。

看懂了添加记录,其他诸如删、改、查的操作也就不难看懂了,大家可以去官网查看相关例子:

https://eosio-cpp.readme.io/d&#8230;

结束语

本章我们学习了:

  • 如何自定义索引;
  • 如何生成以及使用迭代器;
  • 索引和迭代器是如何配合使用的;
  • multi_index的相关操作

希望大家学完之后可以去官网继续补充删、改、查的相关例子,以达到举一反三的效果。下面几篇我们将正式了解EOS智能合约开发的二三事。


推荐阅读
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
author-avatar
j7988l28
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有