基于以太坊的智能合约开发Solidity(内存&结构体篇)

这篇具有很好参考价值的文章主要介绍了基于以太坊的智能合约开发Solidity(内存&结构体篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

参考教程:【内存、引用与持久化存储】1、内存与区块链——storage与memory原理_哔哩哔哩_bilibili

1、storage与memory:

pragma solidity ^0.5.17;

contract MemoryTest
{
uint z = 1;   //这是在合约中定义的状态变量,它会永久地(随本合约)存储在区块链上,也就是storage中,直至合约被销毁

    function add(uint num) public view returns(uint)
    {
        num += 1;  //对函数形参进行修改,但是函数形参仅存储在内存,也就是memory,当函数执行完成,形参随之被销毁
        
        return num;
    }
    
    function test() public view returns(uint,uint)
    {
        uint i = 2;  //这是在函数内部定义的变量,也存储在内存memory中,当函数执行完成也会被销毁
        
        uint j =  add(i);  //把i作为参数传入add函数中,add函数会为i建立副本,在add中对生成的形参副本进行修改,不会影响i本身的值
        
        return(i,j);
    }
}

(1)所有的复杂类型,即数组、结构和映射类型,都有一个额外属性——“数据位置”,用来说明数据是保存在内存memory中还是存储storage中,保存在memory中的数据,在函数执行完毕后空间会被释放,而保存在storage中的数据会随合约一直存储在区块链上。

(2)根据上下文不同,大多数时候数据有默认的位置,但也可以通过在类型名后增加关键字storage或 memory 进行修改。

(3)函数参数(包括返回的参数)的数据位置默认是 memory,局部变量的数据位置默认是memory,状态变量的数据位置强制是storage。

(4)另外还存在第三种数据位置——calldata ,这是一块只读的,且不会永久存储的位置,用来存储函数参数;外部函数的参数(非返回参数)的数据位置被强制指定为 calldata ,效果跟 memory 差不多。

(5)公开可见(publicly visible)的函数参数一定是 memory 类型,如果要求是 storage 类型 则必须是 private 或者 internal 函数,这是为了防止随意的公开调用占用资源。

2、storage引用:

pragma solidity ^0.5.17;

contract StorageTest
{
    
    uint[] arrx;  //这个变量定义在storage中,也就是随合约写在区块链中
    
    function test(uint[] memory arry) public returns(uint)  //用memory修饰的变量,定义在内存中,它可以在函数体内部正常使用,和一般的变量没多少区别
    {
        arrx = arry;   //把内存中的arry赋给区块链中的arrx,arrx会被改变
        
        uint[] storage z = arrx;  //在函数体内部定义一个可变长度的数组时,若声明是storage类型(该版本编译器没有默认storage,必须声明)
        //它就相当于一个指针(或者C++中的引用),指向区块链上的arrx,当修改z的时候,实际上操作的是区块链上的arrx(仅限于数组、mapping类型和结构体有这种语法)
        
        z[0] = 100;  //实际上修改了区块链上的arrx
        
        z.length = 100;  //实际上修改了区块链上arrx的长度
        
        return z[0];
}

    // 返回arrx的第一个元素
    function test2() public returns(uint)
    {
        return arrx[0];
    }
    
    // 返回arrx的长度
    function test3() public returns(uint)
    {
        return arrx.length;
    }
        
}

3、结构体:

(1)定义及初始化:

pragma solidity ^0.5.17;

contract StructTest
{
    //定义一个结构体(在合约内部定义)
    struct Student
    {
        string name;
        uint grade;
        //Student student;  与其它语言一样,禁止结构体内部包含自己(否则创建结构体时会无限开辟空间)
        //Student[] student;  不过结构体中可以定义自己的动态长度数组,其初始长度为0,不会无限开辟空间
        //mapping(uint=>Student) Map;  //通过mapping也可以包含自己
    }
        
    function init() public view returns(string memory,uint)
    {
        // 初始化方式一
        Student memory s = Student("lalala",100);  
        //函数体内部创建结构体必须加memory,否则会认为这是创建一个指向storage中结构体的指针,会报错(动态长度数组同理)
        return(s.name,s.grade);
    }
        
    function init2() public view returns(string memory,uint)
    {
        // 初始化方式二   
        Student memory s = Student({name:"lalala",grade:100});
        //在初始化结构体时可以带上变量的名称
        return(s.name,s.grade);
    }
    
}

(2)mapping特性:

pragma solidity ^0.5.17;

contract StructTest
{
    struct Student
    {
        string name;
        uint grade;
        mapping(uint=>string) Map;  
    }
    
Student s2;

    function init() public returns(string memory,uint)
    {
        //结构体中存在mapping时,初始化结构体可以忽视mapping
        Student memory s = Student("lalala",100);

        //但是memory类型结构体对象是不能直接操作mapping属性变量的
        // s.Map[0] = "wawawa";

        //这时可以在函数体外部创建一个变量,把内存中的s复制给外部的变量,通过外部变量进行操作
        s2 = s;
        s2.Map[0] = "wawawa";

        return(s2.name,s2.grade);
    }
}

(3)结构体作为函数参数:

pragma solidity ^0.5.17;

contract StructTest
{
    struct Student
    {
        string name;
        uint grade;
    }
    
    //结构体作为函数参数时,函数必须用internal修饰
    function test(Student memory student) internal
    {
        Student memory stu = student;  //结构体作为形参不能直接赋值给storage类型的结构体,除非形参中的结构体也用storage修饰
    }
}

4、结构体中storage和memory的类型转换:

(1)storage=>storage:

pragma solidity ^0.5.17;

contract StructTest
{
    struct Student
    {
        string name;
        string grade;
    }
    
    Student student;  //合约状态变量的类型为storage
    
    function getStudent(Student storage stu) internal returns(Student memory)
    {
        Student storage stu1 = stu;  //函数体内部定义指针,指向传入的函数形参,而函数形参stu又指向状态变量student(也可看作是C++中的引用)
        
        stu1.name = "lalala";
        stu1.grade = "10000";  //通过stu1指针(也可以理解为C++中的引用)能修改状态变量student
        
        return stu1;
    }
    
    function test() public returns(string memory) 
    {
        return getStudent(student).name;  //所调用的函数形参是storage类型,可以通过编译
    }
}

(2)memory=>storage:

pragma solidity ^0.5.17;

contract StructTest
{
    struct Student
    {
        string name;
        string grade;
    }
    
    Student student;
    
    function getStudent(Student memory stu) internal returns(Student memory)
    {
        student = stu;  //直接将传进函数的结构体stu拷贝到状态变量student中
        
        stu.name = "lalala";  //修改函数形参,对tmp以及student都不会有影响
        stu.grade = "100";

        //student = stu;  如果在这里再进行拷贝,那么student就会受影响,因为是将修改后的stu拷贝到student中
        
        return stu;
    }
    
    function test() public returns(string memory) 
    {
        Student memory tmp = Student("wangxiaoer","60");  //在函数体内部创建结构体变量
        
        getStudent(tmp);  //把在内存中创建的结构体变量当作参数传入函数中
         
        return student.name;
    }
}

(3)storage=>memory:

pragma solidity ^0.5.17;

contract StructTest
{
    struct Student
    {
        string name;
        string grade;
    }
    
    Student student = Student("wangxiaoer","60");
    
    function getStudent(Student storage stu) internal returns(Student memory)
    {
        Student memory student2 = stu;  //把stu指向(或引用)的student的内容赋给内存中的student2
        
        student2.name = "lalala";  //修改内存中的student2,不会影响storage中的student
        
        student2.grade = "100";
        
        return student2;
    }
    
    function test() public returns(string memory) 
    {
        getStudent(student);
         
        return student.name;
    }
}

(4)memory=>memory:文章来源地址https://www.toymoban.com/news/detail-758274.html

pragma solidity ^0.5.17;

contract StructTest
{
    struct Student
    {
        string name;
        string grade;
    }
    
    function getStudent(Student memory stu) internal returns(Student memory)
    {
        Student memory ter = stu;  //stu是指向内存中meimei的指针,但它却是memory类型,所以ter也是指向meimei的指针
        
        ter.name = "lalalalala";  //通过ter竟然可以修改meimei
        
        ter.grade = "90";
        
        return ter;
    }
    
    function test() public returns(string memory) 
    {
        Student memory meimei = Student("meimei","3");
        
        getStudent(meimei);  //memory实参转给memory形参是指针指向(记住就好,不建议去理解)
         
        return meimei.name;
    }
}

5、枚举体:

pragma solidity ^0.5.17;

contract EnumTest
{
    enum grade{first,second,third}  //定义枚举,first的值为0,second的值为1,以此类推

    grade mingming = grade.first;  //创建枚举变量

    function getEnum() public view returns(grade)
    {
        return mingming;  //返回值为uint8:0
    }

    function getEnum2() public view returns(grade)
    {
        return grade.second;  //返回值为uint8:1
    }

}

到了这里,关于基于以太坊的智能合约开发Solidity(内存&结构体篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 以太坊智能合约开发:Solidity语言中的映射

    本文我们介绍Solidity语言中的映射,包括映射的基本定义、语法、映射的变量声明和基本读写操作。并且通过两个智能合约例子演示了映射的定义与基本操作。 Solidity中关于映射的一些定义: 映射以键-值对(key = value)的形式存储数据; 键可以是任何内置数据类型,包括字节

    2024年02月05日
    浏览(45)
  • 以太坊智能合约开发:Solidity 语言中的数据类型

    本文我们介绍Solidity语言的数据类型,重点是值类型,包括布尔类型、整型、地址类型、字节类型、字符串类型和枚举类型。并且通过两个智能合约例子,用于演示这些数据类型的声明与使用方法。 访问 Github 仓库 获取更多资料。 Solidity中关于数据类型的定义如下: Solidity是

    2024年02月02日
    浏览(56)
  • 以太坊智能合约开发:Solidity语言中的构造函数

    Solidity语言中关于构造函数的定义: 构造函数是使用 constructor 声明的一个可选函数; 构造函数只在合约部署时调用一次,并用于初始化合约的状态变量; 如果没有显式定义的构造函数,则由编译器创建默认构造函数。 构造函数声明语法如下: 其中: ** constructor :

    2024年02月01日
    浏览(45)
  • 《区块链原理与技术》学习笔记(四) ——以太坊的基本架构、账户模型和智能合约

    《区块链原理与技术》学习笔记 第四部分 三、以太坊 1. 以太坊简介 1.1 以太坊发展的阶段 1.2 以太坊与比特币对比 2. 以太坊的基本架构及原理 2.1 基本概念 2.2 状态转移 2.3 基本架构 3. 账户模型与转账 3.1 账户模型 4. 智能合约 4.1 合约账户与数据存储 4.2 驱动智能合约 以太坊

    2024年02月13日
    浏览(37)
  • 以太坊智能合约语言Solidity - 3 数组

    1字节(Byte) = 8位 (bit), bytes32 = 256位,bytes1 实质上就等于 int8 固定长度的数组一旦被定义就无法再更改,并且长度在一开始就会被显式定义 我们再来创建一个新的文件用来编写代码 字节数组无法进行基本运算,但是可以比较 字节数组还支持其他一些逻辑运算,具体计算结果

    2023年04月08日
    浏览(48)
  • 第四章 以太坊智能合约solidity介绍

    Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言,设计的目的是能在以太坊虚拟机上运行。 本章大概介绍合约的基本信息,合约的组成,语法方面不做过多的介绍,个人建议多阅读官方文档效果更佳,后续的章节会开发ERC20代币合约案例以便于更好的学习智

    2024年02月06日
    浏览(47)
  • 以太坊的ecrecover预编译合约

    前序博客: ECDSA VS Schnorr signature VS BLS signature ECDSA,全称为Elliptic curve Digital Signature Algorithm,采用Elliptic curve cryptography来实现的数字签名算法。 公私钥对 ( p k , P ) (pk,P) ( p k , P ) ,其中公钥 P = p k × G P=pktimes G P = p k × G , G G G 为所选椭圆曲线的base point。(elliptic curve base po

    2024年02月02日
    浏览(34)
  • 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一)

    前面一篇关于 智能合约 翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用 程序语言 去编写 智能合约 了。 而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂 智能合约 代码,或找出其中的漏洞,那么,学习 Solidity 这门高级的智能合约语言是有

    2023年04月16日
    浏览(84)
  • solidity:智能合约结构介绍

    合约结构介绍 1.SPDX 版权声明 bytecode metadata 介绍 2.pragma solidity 版本限制 3.contract 4.import 导入声明 5.interface: 接口 6.library:库合约 第 1 行 // SPDX-License-Identifier: MIT 就是合约的版权声明。其中 SPDX-License-Identifier (SPDX 许可标示) 是标注当前的智能合约采用什么样的对外开放标

    2023年04月08日
    浏览(33)
  • Solidity智能合约开发 — 3.4-抽象智能合约和接口

    假如一个智能合约中至少一个函数缺省实现时,即某个函数缺少{}中的内容,这个智能合约就当做抽象智能合约。 当我们有一个函数没想好怎么写时,必须将该合约标为 abstract ,不然编译会报错;另外,未实现的函数需要加 virtual ,以便子合约重写。抽象智能合约是将智能合

    2024年02月12日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包