01 Solidity--

第一个 Solidity 程序

Solidity 是一种用于编写以太坊虚拟机(EVM)智能合约的编程语言。

掌握 Solidity 是参与链上项目的必备技能

在 Remix 中,左侧菜单有三个按钮,分别对应文件(编写代码)、编译(运行代码)和部署(将合约部署到链上)。点击“创建新文件”(Create New File)按钮,即可创建一个空白的 Solidity 合约。

在这里插入图片描述

编写代码

//1 行是注释,说明代码所使用的软件许可(license),这里使用的是 MIT 许可。如果不写许可,编译时会出现警告(warning),但程序仍可运行
// SPDX-License-Identifier: MIT

//2 行声明源文件所使用的 Solidity 版本,因为不同版本的语法有差异。这行代码表示源文件将不允许小于 0.8.21 版本或大于等于 0.9.0 的编译器编译(第二个条件由 ^ 提供)。
pragma solidity ^0.8.21;

//3-4 行是合约部分。第 3 行创建合约(contract),并声明合约名为 HelloWeb3。第 4 行是合约内容,声明了一个 string(字符串)变量 _string,并赋值为 "Hello Web3!"。
contract HelloWeb3{
    string public _string = "Hello Web3!";
}

编译并部署代码

在 Remix 编辑代码的页面,按 Ctrl + S 即可编译代码。

编译完成后,点击左侧菜单的“部署”按钮,进入部署页面。
在这里插入图片描述

Remix 会使用 Remix 虚拟机(以前称为 JavaScript 虚拟机)来模拟以太坊链,运行智能合约,类似在浏览器里运行一条测试链。
Remix 还会为你分配一些测试账户,每个账户里有 100 ETH(测试代币),随意使用。

点击 Deploy(黄色按钮),即可部署我们编写的合约。

部署成功后,在下方会看到名为 HelloWeb3 的合约。点击 _string,即可看到 “Hello Web3!”。

在这里插入图片描述

变量

  • 值类型(Value Type):包括布尔型,整数型等等,这类变量赋值时候直接传递数值。

  • 引用类型(Reference Type):包括数组和结构体,这类变量占空间大,赋值时候直接传递地址(类似指针)。

  • 映射类型(Mapping Type): Solidity中存储键值对的数据结构,可以理解为哈希表

  • public、private、internal 用于修饰状态变量。

    • public 变量会自动生成同名的 getter 函数,用于查询数值。
    • 未标明可见性类型的状态变量,默认为 internal。

状态变量和非状态变量

  • 状态变量通常位于合约的顶部,并且是合约的一部分。这些变量保存在存储(storage)中,并且在整个合约生命周期内都是可用的。
  • 非状态变量指的是在函数内部声明的变量,它们仅在函数执行期间存在,并且不在合约的存储空间中保存。

值类型

  • 布尔型
  • 整型
  • 地址类型
    • 访问修饰符修饰的 address: 存储一个 20 字节的值(以太坊地址的大小)。
    • payable 修饰的 address: 比普通地址多了 transfer 和 send 两个成员方法,用于接收转账。
// 地址
address public _address = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
address payable public _address1 = payable(_address); // payable address,可以转账、查余额
// 地址类型的成员
uint256 public balance = _address1.balance; // balance of address
  • 定长字节数组
  • 定长字节数组: 属于值类型,数组长度在声明之后不能改变。根据字节数组的长度分为 bytes1, bytes8, bytes32 等类型。定长字节数组最多存储 32 bytes 数据,即bytes32。
  • 不定长字节数组: 属于引用类型(之后的章节介绍),数组长度在声明之后可以改变,包括 bytes 等。
// 固定长度的字节数组
bytes32 public _byte32 = "MiniSolidity"; 
bytes1 public _byte = _byte32[0]; 
在上述代码中,MiniSolidity 变量以字节的方式存储进变量 _byte32。如果把它转换成 16 进制,就是:0x4d696e69536f6c69646974790000000000000000000000000000000000000000

_byte 变量的值为 _byte32 的第一个字节,即 0x4d
  1. 枚举 enum
    枚举(enum)是 Solidity 中用户定义的数据类型。它主要用于为 uint 分配名称,使程序易于阅读和维护。它与 C 语言 中的 enum 类似,使用名称来代替从 0 开始的 uint:
// 用enum将uint 012表示为Buy, Hold, Sell
enum ActionSet { Buy, Hold, Sell }
// 创建enum变量 action
ActionSet action = ActionSet.Buy;
枚举可以显式地和 uint 相互转换,并会检查转换的正整数是否在枚举的长度内,否则会报错:

// enum可以和uint显式的转换
function enumToUint() external view returns(uint){
    return uint(action);
}

引用类型

数组

函数

funtion <function name> <access modifier> [pure|view|payable] (<parameter types>) [returns (<return types>)] {
    // 函数体
}
  • function:``声明函数时的固定开头
  • :``函数名
  • ():``圆括号内写入函数的参数,即输入到函数的变量类型和名称。
  • 必须指明可见性。函数可见性说明符,共有4种。
    • public:内部和外部均可见。
    • private:只能从本合约内部访问,继承的合约也不能使用。
    • external:只能从合约外部访问(但内部可以通过 this.f() 来调用,f是函数名)。
    • internal: 只能从合约内部访问,继承的合约可以用。
  • [pure|view|payable]:非必须,不写时默认为 nonpayable。决定函数权限/功能的关键字。
    • payable:以这个关键字修饰的函数,运行的时候可以给合约转入 ETH。
    • pure 和 view :声明该函数不改变链上状态。
  • [returns ()]:非必须。返回值的类型和名称。

pure 和 view

ETH 中任意会改变链上状态的操作都会被收取燃料费(gas fee),例如:

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

solidity 引入这两个关键字,核心原因是以太坊交易需要支付燃料费(gas fee)。gas fee 很贵,但如果计算不改变链上状态,就可以不用付 gas。

合约的状态变量存储在链上,如果任何操作都改变状态变量的链上状态,合约的代价是很高的。
此时,可以在函数增加 pure / view 关键字,此时函数内的任何操作不会改变链上状态。因此用户直接调用它们是不需要付 gas 的(注意,合约中非 pure/view 函数调用 pure/view 函数时需要付gas)。

  • pure 函数既不能读取也不能写入链上的状态变量。
  • view 函数能读取但也不能写入状态变量。
  • pure 或 view 的函数既可以读取也可以写入状态变量。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
contract FunctionTypes{

    // 在合约里定义一个状态变量 number,初始化为 5。
    uint256 public number = 5;
}

// 定义一个 add() 函数,每次调用会让 number 增加 1。
function add() external{
    number = number + 1;
}

如果 add() 函数被标记为 pure,比如 function add() external pure,就会报错。因为 pure 是不能读取合约里的状态变量的,更不配改写。

// 报错
function add() external pure{
    number = number + 1;
}

在这里插入图片描述

纯函数 Pure Function

用 pure 修饰的函数即为纯函数。
纯函数指的是那些只依赖于其输入参数,并且除了返回值之外没有任何副作用的函数。这意味着纯函数不修改外部状态,也不依赖于外部状态。这样的函数对于确保代码的可预测性和简化调试非常有用。

例如,给函数传入的参数是一个非状态变量 number,返回的依然是非状态变量 new_number ,这个操作不会读取或写入状态变量。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
contract FunctionTypes{

// 没有状态变量,都是暂时性的非状态变量
function addPure(uint256 number) external pure returns(uint256 new_number){
    new_number = number + 1;
}
}

部署后,在右侧填传入的参数(number),下侧即可看到返回的参数(new_number)
在这里插入图片描述

internal & external

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

出于安全考虑,尽量将函数设置为 internal。
在不得不从外部访问的时候,可以通过合约内的 external 间接调用。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
contract MathContract {
    uint256 public number; // 声明一个公共变量 number

// 定义一个 internal 的 minus() 函数,每次调用使得 number 变量减少 1。
    function minus() internal {
        number = number - 1;
    }

// 由于 internal 函数只能由合约内部调用,我们必须再定义一个 external 的 minusCall() 函数,
// 通过它间接调用内部的 minus() 函数。
    function minusCall() external {
        minus(); // 调用内部函数来减少 number
    }

    // 用于设置初始值
    function setNumber(uint256 _number) public {
        number = _number;
    }
}

在这里插入图片描述
按照这样的顺序,就能在外部调用内部函数,改变状态变量。

payable

如果你希望智能合约能够接收Ether作为资金来源,例如作为运营资金,那么接收这些转账的函数需要标记为 payable。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
contract MathContract {
    uint256 public number; // 声明一个公共变量 number

    // internal 函数,减少 number 的值
    function minus() internal {
        number = number - 1;
    }

    // external 函数,允许外部调用 minus()
    function minusCall() external {
        minus(); // 调用内部函数来减少 number
    }

    // 示例函数,用于设置初始值
    function setNumber(uint256 _number) public {
        number = _number;
    }

	// external payable 的 minusPayable() 函数,间接调用 minus(),并且返回合约里的 ETH 余额(this 关键字可以让我们引用合约地址)。
    function minusPayable() external payable returns(uint256 balance) {
    minus();    
    balance = address(this).balance;
}
}

在调用 minusPayable() 时往合约里转入1个 ETH。
在这里插入图片描述
通过这个操作,最终每执行一次 minusPayable,都会往账户里存入 1ETH。

return

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891376.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring ApplicationContext初始化过程

Spring-01篇章 一、Spring 简介 Spring是一个开源的Java平台&#xff0c;它提供了全面的基础设施支持来帮助Java开发者更容易地开发Java应用程序。Spring框架的核心特点是依赖注入&#xff08;DI&#xff09;和面向切面编程&#xff08;AOP&#xff09;&#xff0c;这些使得开…

【H2O2|全栈】JS入门知识(一)

目录 JS入门 前言 准备工作 JS标签和文件 变量 数据类型 字符串 变量的交换 数据类型获取 数据类型转换 面试题 提问框和提示框 提问框 提示框 ​编辑​编辑控制台输出 ​编辑转义字符 结束语 JS入门 前言 本系列博客主要分享JavaScript的基础语法知识&…

RNA-seq全流程

第一部分&#xff1a;脚本的初始设置与参数解析 #!/bin/bash# 检查输入参数 if [ "$#" -lt 1 ]; thenecho "Usage: $0 -f <sample_file> -d <data_directory> -s <script_directory> -g <group_file>"exit 1 fi# 使用 R 语言的 a…

2025推荐选题|基于Springboot和vue的智慧阅读管理系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

Java - WebSocket

一、WebSocket 1.1、WebSocket概念 WebSocket是一种协议&#xff0c;用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接&#xff0c;这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发&#xff0c;并于2…

【CSS】houdini自定义CSS属性实现渐变色旋转动画

现有一段代码&#xff0c;在不旋转整个元素的前提下&#xff0c;渐变背景无法应用动画 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initia…

专业模拟训练头显,Varjo XR-4 如何开启虚拟仿真新模拟时代

虚拟仿真模拟训练是提升技能熟练度与工作安全性的有效解决方案&#xff0c;Varjo XR-4作为专业模拟训练头显&#xff0c;凭借其出色的技术特性和性能&#xff0c;正在引领虚拟仿真模拟训练进入一个全新的时代。 一、卓越的视觉体验 高分辨率显示器&#xff1a;Varjo XR-4配备…

计算机毕业设计 基于Python的美术馆预约系统的设计与实现 Python毕业设计 Python毕业设计选题【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

三子棋(C 语言)

目录 一、游戏设计的整体思路二、各个步骤的代码实现1. 菜单及循环选择的实现2. 棋盘的初始化和显示3. 轮流下棋及结果判断实现4. 结果判断实现 三、所有代码四、总结 一、游戏设计的整体思路 &#xff08;1&#xff09;提供一个菜单让玩家选择人机对战、玩家对战或者退出游戏…

大厂面试真题-组合和聚合的区别是什么

组合和聚合比较类似&#xff0c;二者都表示整体和部分之间的关系。 聚合关系的特点是&#xff1a;整体由部分构成&#xff0c;但是整体和部分之间并不是强依赖的关系&#xff0c;而是弱依 赖的关系&#xff0c;也就是说&#xff0c;即使整体不存在了&#xff0c;部分仍然存在…

Zabbix监控vCenter虚拟机

1. vcenter上配置snmp agent 如果配置 vCenter Server Appliance SNMP 代理以用于轮询,则它可以侦听和响应来自 SNMP 管理客户端系统的请求,如 GET、GETNEXT 和 GETBULK 请求. 使用root身份进入vcenter命令行,开启snmp代理 Command> snmp.enable Command> snmp.set…

正则表达式 | Python、Julia 和 Shell 语法详解

正则表达式在网页爬虫、脚本编写等众多任务中都有重要的应用。为了系统梳理其语法&#xff0c;以及 Python、Julia 和 Shell 中与正则表达式相关的工具&#xff0c;本篇将进行详细介绍。 相关学习资源&#xff1a;编程胶囊。 基础语法 通用语法 在大多数支持正则表达式的语…

24/10/14 视觉笔记 图像拼接融合

图像拼接分为四步 1.特征点提取 2.特征点匹配 3.仿射矩阵计算 4.图像拼接与融合 1.特征提取 找到图像中具有显著性信息点&#xff0c;并计算该点的特征表达 def detectAndDescrible(img):#构建STFT特征检测器sift cv2.SIFT_create()#特征提取kps,features sift.detectA…

3-3 AUTOSAR RTE 对SR Port的实现

返回总目录->返回总目录<- 目录 一、前言 二、显式访问 三、隐式访问 四、队列调用(Queued) 五、无效数据元素 一、前言 RTE作为SWC和BSW之间的通信机构,支持Sender-Receiver方式实现ECU内及ECU间的通信。 对于Sender-Receiver Port支持三种模式: 显式访问:若…

京东零售数据湖应用与实践

作者&#xff1a;陈洪健&#xff1a;京东零售大数据架构师&#xff0c;深耕大数据 10 年&#xff0c;2019 年加入京东&#xff0c;主要负责 OLAP 优化、大数据传输工具生态、流批一体、SRE 建设。 当前企业数据处理广泛采用 Lambda 架构。Lambda 架构的优点是保证了数据的完整性…

LeetCode|70.爬楼梯

这道题很像斐波那契数列&#xff0c;但是初始值不同&#xff0c;也有动态规划的解法&#xff0c;但是一开始我想到的是递归写法。现在我们站在第n阶台阶&#xff0c;那么&#xff0c;我们上一步就有两种可能&#xff1a;1、我们从第n-1阶台阶走一步上来的&#xff1b;2、我们从…

弹出“xinput1_3.dll文件缺失”的错误要怎么处理?一键修复xinput1_3.dll

当你尝试打开游戏或应用时&#xff0c;如果弹出“xinput1_3.dll文件缺失”的错误&#xff0c;请记得及时处理。这个文件是DirectX中用于处理游戏控制器输入的关键组件。这个问题可以通过几个简单的步骤轻松解决。本指南将教你如何快速恢复或替换丢失的xinput1_3.dll文件&#x…

免费Excel工作表同类数据合并工具

下载地址&#xff1a;https://pan.quark.cn/s/81b1aeb45e4c 在 Excel 表格里&#xff0c;当我们试图手动将多行同类数据合并为一行时&#xff0c;会遭遇诸多棘手的困难以及繁杂的操作流程。在确定哪些数据属于可合并的同类数据时&#xff0c;单纯依靠人工进行对比&#xff0c;极…

SQL数据库刷题sql_day33(连续3次为球队得分的球员名单)

描述 两支篮球队进行了激烈的比赛&#xff0c;比分交替上升。比赛结束后&#xff0c;你有一个两队分数的明细表&#xff08;名称为“分数表”&#xff09;。 表中记录了球队、球员号码、球员姓名、得分分数及得分时间。现在球队要对比赛中表现突出的球员进行奖励。 问题&#x…

用最短长度的绳子把整个花园围起来

给定一个数组 trees&#xff0c;其中 trees[i] [xi, yi] 表示树在花园中的位置。 你被要求用最短长度的绳子把整个花园围起来&#xff0c;因为绳子很贵。只有把 所有的树都围起来&#xff0c;花园才围得很好。 返回恰好位于围栏周边的树木的坐标。 示例 1: 输入: points […