【从0学习Solidity】 3. 函数详解

2023-09-22 11:08:38

【从0学习Solidity】 3. 函数详解

在这里插入图片描述

  • 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。
  • 关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!
  • 本文收录于 不写代码没饭吃 的学习汇报系列,大家有兴趣的可以看一看。
  • 欢迎访问我们的微信公众号:不写代码没饭吃,获取更多精彩内容、实用技巧、行业资讯等。您关注的是我们前进的动力!

函数

Solidity语言的函数非常灵活,可以进行各种复杂操作。在本教程中,我们将会概述函数的基础概念,并通过一些示例演示如何使用函数。

我们先看一下 Solidity 中函数的形式:

    function <function name>(<parameter types>) {internal|external|public|private} [pure|view|payable] [returns (<return types>)]

看着有一些复杂,让我们从前往后逐个解释(方括号中的是可写可不
写的关键字):

  1. function:声明函数时的固定用法。要编写函数,就需要以 function 关键字开头。

  2. <function name>:函数名。

  3. (<parameter types>):圆括号内写入函数的参数,即输入到函数的变量类型和名称。

  4. {internal|external|public|private}:函数可见性说明符,共有4种。

    • public:内部和外部均可见。
    • private:只能从本合约内部访问,继承的合约也不能使用。
    • external:只能从合约外部访问(但内部可以通过 this.f() 来调用,f是函数名)。
    • internal: 只能从合约内部访问,继承的合约可以用。

    注意 1:合约中定义的函数需要明确指定可见性,它们没有默认值。

    注意 2public|private|internal 也可用于修饰状态变量。public变量会自动生成同名的getter函数,用于查询数值。未标明可见性类型的状态变量,默认为internal

  5. [pure|view|payable]:决定函数权限/功能的关键字。payable(可支付的)很好理解,带着它的函数,运行的时候可以给合约转入 ETH。pureview 的介绍见下一节。

  6. [returns ()]:函数返回的变量类型和名称。

到底什么是 PureView

刚开始学习 solidity 时,pureview 关键字可能令人费解,因为其他编程语言中没有类似的关键字。solidity 引入这两个关键字主要是因为 以太坊交易需要支付气费(gas fee)。合约的状态变量存储在链上,gas fee 很贵,如果计算不改变链上状态,就可以不用付 gas。包含 pureview 关键字的函数是不改写链上状态的,因此用户直接调用它们是不需要付 gas 的(注意,合约中非 pure/view 函数调用 pure/view 函数时需要付gas)。

在以太坊中,以下语句被视为修改链上状态:

  1. 写入状态变量。
  2. 释放事件。
  3. 创建其他合约。
  4. 使用 selfdestruct.
  5. 通过调用发送以太币。
  6. 调用任何未标记 viewpure 的函数。
  7. 使用低级调用(low-level calls)。
  8. 使用包含某些操作码的内联汇编。

为了帮助大家理解,我画了一个马里奥插图。在这幅插图中,我将合约中的状态变量(存储在链上)比作碧琪公主,三种不同的角色代表不同的关键字。

在这里插入图片描述

  • pure,中文意思是“纯”,这里可以理解为”纯打酱油的”。pure 函数既不能读取也不能写入链上的状态变量。就像小怪一样,看不到也摸不到碧琪公主。

  • view,“看”,这里可以理解为“看客”。view函数能读取但也不能写入状态变量。类似马里奥,能看到碧琪公主,但终究是看客,不能入洞房。

  • pureview 的函数既可以读取也可以写入状态变量。类似马里奥里的 boss,可以对碧琪公主为所欲为🐶。

代码

1. pure 和 view

我们在合约里定义一个状态变量 number,初始化为 5。

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    contract FunctionTypes{
        uint256 public number = 5;
    }

定义一个 add() 函数,每次调用会让 number 增加 1。

    // 默认
    function add() external{
        number = number + 1;
    }

如果 add() 函数被标记为 pure,比如 function add() pure external,就会报错。因为 pure 是不配读取合约里的状态变量的,更不配改写。那 pure 函数能做些什么?举个例子,你可以给函数传递一个参数 _number,然后让他返回 _number + 1,这个操作不会读取或写入状态变量。

    // pure:
    function addPure(uint256 _number) external pure returns(uint256 new_number){
        new_number = _number + 1;
    }

在这里插入图片描述

如果 add() 函数被标记为 view,比如 function add() view external,也会报错。因为 view 能读取,但不能够改写状态变量。我们可以稍微改写下函数,读取但是不改写 number,返回一个新的变量。

    // view: 看客
    function addView() external view returns(uint256 new_number) {
        new_number = number + 1;
    }

在这里插入图片描述

2. internal v.s. external

    // internal: 内部函数
    function minus() internal {
        number = number - 1;
    }

    // 合约内的函数可以调用内部函数
    function minusCall() external {
        minus();
    }

我们定义一个 internalminus() 函数,每次调用使得 number 变量减少 1。由于 internal 函数只能由合约内部调用,我们必须再定义一个 externalminusCall() 函数,通过它间接调用内部的 minus() 函数。
在这里插入图片描述

3. payable

    // payable: 递钱,能给合约支付eth的函数
    function minusPayable() external payable returns(uint256 balance) {
        minus();    
        balance = address(this).balance;
    }

我们定义一个 external payableminusPayable() 函数,间接的调用 minus(),并且返回合约里的 ETH 余额(this 关键字可以让我们引用合约地址)。我们可以在调用 minusPayable() 时往合约里转入1个 ETH。

我们可以在返回的信息中看到,合约的余额变为 1 ETH。

在这里插入图片描述

总结

在这一讲,我们介绍了 Solidity 中的函数。pureview 关键字比较难理解,在其他语言中没出现过:view 函数可以读取状态变量,但不能改写;pure 函数既不能读取也不能改写状态变量。

在这里插入图片描述

如果这份博客对大家有帮助,希望各位给作者一个免费的点赞👍作为鼓励,并评论收藏一下⭐,谢谢大家!!!
制作不易,如果大家有什么疑问或给作者的意见,欢迎评论区留言。

更多推荐

Linux的调试工具 - gdb(超详细)

Linux的调试工具-gdb1.背景2.开始使用指令的使用都用下面这个C语言简单小代码来进行演示:1.list或l行号:显示文件源代码,接着上次的位置往下列,每次列10行。2.list或l函数名:列出某个函数的源代码。3.r或run:运行程序。4.break或b行号:在某一行设置断点5.n或next:单条执行(类似vs

RK3568驱动指南|第五篇 中断-第42章 软中断实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和MaliG522EE图形处理器。RK3568支持4K解码和1080P编码,支持SATA/PCIE/USB3.0外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568支持安卓11和li

快速排序模拟实现

快速排序,时间复杂度为O(NlogN),属于排序中相对快的那一列,以下是快排的模拟实现:法一:左右指针交换法voidswap(int*x,int*y){inttmp=*x;*x=*y;*y=tmp;}//交换函数intgetmid(int*a,intleft,intright){intmid=(left+right)/

【错误记录】IntelliJ IDEA 导出可执行 jar 包执行报错 ( java.lang.ClassNotFoundException | 打包时没有选择依赖库 )

文章目录一、报错信息二、解决方案一三、解决方案二一、报错信息参考【IntelliJIDEA】导出可执行JAR包博客,从IntelliJIDEA中导出可执行JAR包;执行菜单栏/Build/BuildArtifacts选项,编译Module中配置的artifacts项目;编译完成artifacts后,进入到工程目录\ou

汽配制造问题以及MES管理系统解决方案

在汽车工业中,零部件制造与整车制造有着显著的不同。这些差异导致了零部件制造的复杂性和高要求,使其成为一个高度综合的最终产品。本文将详细介绍这些差异以及针对这些差异的解决方案。一、行业特点决定需求汽车配件制造与整车制造存在较大不同。在整车制造过程中,装配是最复杂的环节,而在零部件制造过程中,装配所占的比重较小,机加等前端

XSS跨站脚本攻击

XSS全称(CrossSiteScripting)跨站脚本攻击,XSS属于客户端攻击,受害者最终是用户,在网页中嵌入客户端恶意脚本代码,最常用javascript语言。(注意:叠成样式表CSS已经被占用所以叫XSS)原因:输入没过滤,输出没编码。危害:劫持用户cookie,钓鱼,挂马分类:1、反射性XSS(中危,一次性

肖sir__项目环境之全流程__005

一、测试流程(h模型)1、需求文档(产品)需求文档(软件需求规格说明书srs)(1)如何分析需求a、显示需求(主流程、功能,业务)b、隐性需求(比如:红包记录,扣款金额=发送金额)c、特殊需求(计算:保费计算,还款计算)d、关联需求(满减活动:活动订单,活动增加,)(2)需求特殊a、完整性:功能的实现和设计信息齐全b、

API接口:概述、设计、应用与未来趋势

一、API接口概述API,全称应用程序接口,是一种软件程序之间的通信方法。API接口在互联网开发中扮演着重要角色,允许不同的应用程序相互交流和共享数据。API定义了一套标准的通信协议,使得开发人员能够使用特定的函数、方法或协议来交换信息。二、API接口设计RESTfulAPIRESTfulAPI是当前最流行的一种API

【SpringMVC】自定义注解与AOP结合使用

目录一、SpringMVC之自定义注解1.1Java注解简介1.2为什么要用注解1.3注解的分类⭐1.3.1JDK基本注解1.3.2JDK元注解1.3.3自定义注解1.4自定义注解三种使用案例1.4.1案例一(获取类与方法上的注解值)1.4.2案例二(获取类属性上的注解属性值)1.4.3案例三(获取参数修饰注解对应的属

吉时利KEYSIGHT6517B静电计6517A高阻计

Keithley6517B静电计/高阻计是灵敏测量的全球研究实验室标准。吉时利静电计拥有60多年的低电平测量专业知识,可提供低至10aA(10×10-18A)的电流水平和低至1fC的电荷水平的可靠测量,以及高达1018Ω的最高电阻测量。6517B还能够测量最大电压范围(高达200V),输入阻抗超过200TO。特征测量高

EPLAN_001#常用功能(一)

一、栅格设置、背景颜色设置二、插入设备图标(快捷键Insert)按TAB旋转方向三、¶通过左CTRL+ENTER输入四、移动属性文本、复制格式CTRL+B可以移动设备图形中的相关文本(或者右键—文本—移动属性文本)很对多个文本的,可以取消其固定五、改变方向(属性中选择相应的变量)六、直接编辑(可以快速修改元器件名称)七

热文推荐