一文聊透 Solidity 语法:助你成为智能合约专家(一)

简介: 一文聊透 Solidity 语法:助你成为智能合约专家

关于区块链和智能合约开发者的区别解释


我发现很多人都表述不清楚区块链和智能合约。我认识几位程序员朋友,他们都自称是在做区块链开发,但实际上是在做智能合约的开发。大多数外行分不清楚区块链和智能合约我能理解,但是很多从事智能合约开发的程序员竟然也分不清楚,我不知道是不是表述问题还是理解问题。

区块链是区块链,智能合约是智能合约,两者的关系就像是微信和微信小程序一样,一个是 App 开发,一个是小程序开发,根本不一样,不能混为一谈。

据我了解,区块链的需求没那么多,特别是中国这个环境下。大多数区块链相关的程序员都是在做智能合约开发,而不是真的在开发区块链。

区块链是可以用很多后端语言去开发的,比如用 Go、Node.js、Rust、Java 等。

但是智能合约不可以随便选择编程语言,我这里讲的智能合约是指以太坊智能合约。目前它只能选择 Solidity、Vyper、YUL、YUL+ 和 Fe 这 5 种语言。其中 solidity 最受欢迎,大多数项目和开发者都是选择了 solidity。我们几乎可以说 solidity 是智能合约的首选编程语言。


这篇文章会讲什么?


这篇文章将会介绍我认为使用 Solidity 编写智能合约时 90% 以上的场景中能够用到的语法和特性。

但是 Solidity 是一门完整的编程语言,想要把它彻底学明白,一篇文章肯定是不够的。因为很多语言都被写成了一厚厚地本书。不过通常写编程语言的书都会非常全体、体系化地介绍语言的全部,包括那些平时压根用不到的知识,或者一些已经落伍,语言设计上糟粕的部分。总体来说,通过一本厚厚的书来讲一门编程语言,多少是从研究的角度出发的,如果你只想快速用 Solidity 开发智能合约,不想把这门语言研究的这么透彻,那么本文很适合你。

同时本文会拿 solidity 和一些面向对象的语言做对比,如果你完全不懂其他编程语言,那么本文不适合你。


面向合约


Solidity 的设计理念和面向对象编程语言很相似,不过 Solidity 是面相合约的编程语言,如果你有面向对象编程语言的开发经验,那么学习 Solidity 就没有那么难。

Solidity 语言被设计为编写合约的语言,目前来说也只能写合约,所以它不像其他语言那样可以做很多事情。


合约构成解读


我们先来看一个最简单的合约构成,做一个整体的感受。


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
  address private owner;
  unit public state;
  modifier onlyOwner() {
    require(msg.sender == owner, "only owner");
    _;
  }
  event StateChanged(unit state);
  constructor() public {
    owner = msg.sender;
  }
  function setState(uint _state) external onlyOwner {
    state = state;
    emit StateChanged(_state)
  }
}

我简单解释下这个合约的代码,不会详细介绍。

第 1 行是指定版本许可。

第 2 行是指定使用的语言版本。

第 4 行是声明一个名为 HelloWorld 的合约。

第 5-6 行是状态变量,它们会永久存储在合约中。

第 8 -11 行是函数修改器,它可以用在函数修饰符上,可以改变函数的行为。

第 13 行是声明一个事件,事件可以被触发和监听。

第 15-17 行是构造函数,在部署时会被调用。

第 19-22 行是声明了一个名为 setState 的函数。


版本


solidity 有很多种版本,目前最新的版本是 8.x。

但是在早期比较流行的是 5.x、6.x 这两个版本。

solidity 的版本命名规范采用 。

和其他大多数编程语言不同的是,solidity 的版本是直接写在源代码里的。

在任意一个 sol 文件的最开始,都应该是版本代码。

语法为:


pragma solidity 0.8.0;

如果你用过 npm 的话,那这个版本语言一定不会陌生,因为 solidity 同样使用了 semver 版本规范。


合约


合约的概念有点像面向对象编程语言的类,属于一等公民。

通过关键字 contract 创建。

语法:


contract MyContract {
}

可以通过 new 关键字创建合约。


new MyContract();


继承


面向对象的语言通常会使用 extends 关键字来继承,但是 solidity 没有这样做,它使用 is 来继承合约。


contract MyContract1 {
  uint256 num = 2022;
}
contract MyContract2 is MyContract1 {
}

子合约被部署时,会把所有父合约的代码一起打包,所以对父合约中函数的调用都属于内部调用。

子合约可以隐式转换父合约,合约也可以显式转换为地址。


address addr = address(c);

重写函数使用 override 关键字。父合约中支持重写的函数必须是 virtual 的。


contract Parent {
    function fn() public virtual {}
}
contract Child is Parent {
    function fn() public override {}
}

调用父合约中的方法,使用 super 关键字。


contract Parent {
    function fn() public {}
}
contract Child is Parent {
    function fn2() public {
        super.fn();
    }
}

支持多重继承。


contract Parent1 {
    function fn() public virtual {}
}
contract Parent2 {
    function fn() public virtual {}
}
contract Child is Parent1, Parent2 {
    function fn() public override(Parent1, Parent2) {}
}


变量与基础类型


变量是永久存储在合约中的值,通常用来记录业务信息。

每个变量都需要声明类型,solidity 中的类型有如下几种:

  • string:字符串类型
  • bool:布尔值,true/false。
  • uint:无符号整型,有 uint 和 uint8/16/32/64/128/256 几个类型。uint 是 uint256 的别名。
  • int:有符号整型,规则和 uint 一样。
  • bytes:定长字节数组。从 bytes1 到 bytes32,byte 是 bytes1 的别名。它和数组类似,通过下标获取元素,通过 length 获取成员数量。
  • address:地址类型。保存一个 20 字节的地址。
  • address payable:可支付的地址,有成员函数 transfer 和 send。


contract MyContract {
  string name = ""
}


uint


对于整型变量,我们可以通过 type(x).min 和 type(x).max 来获取某个类型的最大值和最小值。


address


address payable 可以隐式转换到 address,但是 address 必须通过 payable(address) 这种方式显示转换。

address 还可以显示转换为 uint160 和 bytes20。


bytes 和 string


bytes 和 string 都是数组,而不是普通的值类型。

bytes 和 byte[] 非常像,但是它在 calldata 和 memory 中会紧打包。紧打包的意思是将元素连续存储在一起,不会按照每 32 字节为一个单元进行存储。

string 是变长 utf-8 编码的字节数组,和 bytes 不同的是它不可以用索引来访问。

字符串没有操作函数,一般都是通过第三方 string 库来操作字符串。

string 可以转换为 bytes,转换时是创建引用而不是创建拷贝。


function stringToBytes() public pure returns (bytes memory) {
  string memory str = "hello";
  bytes memory bts = bytes(str);
  return bts;
}

由于 bytes 和 string 很相似,所以我们在使用它们时应该有对应的原则。

  • 对于任意长度的原始字节使用 bytes。
  • 对于任意长度的 UTF-8 字符串使用 string。
  • 当需要对字节数组长度进行限制时,应该使用 byte1-byte32 之间的具体类型。

合理使用 bytes 可以节省 Gas 费。


变量修饰符


我们也可以为变量指定访问修饰符。

语法是 类型 访问修饰符(可选) 字段名。

访问修饰符有三种:

  • public:公开,外部可以访问,声明为 public 的话会自动生成 getter 函数。
  • internal:默认,只有合约自身和派生的合约可以访问。
  • private:只有合约自身可以访问。

solidity 中的变量与传统语言的变量有些不同。

  1. 字符串的值默认不可以包含中文。如果要使用除了英文外的其他语言,必须加 unicode 前缀。


string name = unicode"小明";


结构体


使用关键字 struct 创建结构,有点类似 Go/C 的 struct,或者类似 TypeScript 中的 type/interface。


struct User {
  string name;
  string password;
  uint8 age;
  bool state;
}

初始化结构体和调用函数类似,参数的顺序和结构体的顺序保持一致。


User user = User("章三", "123", 12, false);

访问某一个属性使用点号。


user.name;

属性也可以直接赋值。


user.name = "里斯";


数组


和 TypeScript 中的数组语法一致,语法是 type[]。


User[] users;

访问数组元素,使用 array[index] 的方式。


users[0];

访问不存在的下标,会直接报错。

在创建数组时可以声明长度,如果不声明,那就是可以动态调整大小的数组。


uint256[10] nums;

数组具有 pop 和 push 方法,分别用于弹出一个元素和添加一个元素。但是它们不可以用在定长数组中。

push 方法可以不传递参数,这时表示它添加一个该元素类型的零值。


strs.push("1");
strs.pop();


映射


类似于很多语言中的 Map 结构。语法是 mapping(keyType => valueType)。


mapping(address => User) userMapping;

key 的类型只允许是基本类型,不可以是复杂类型,比如合约、枚举、映射和结构体。

value 的类型没有限制。

访问 mapping 元素,使用 mapping[key] 的方式。


userMapping[0x021221]

访问不存在的 key,会返回 value 类型的默认值。

mapping 不可以作为公有函数的参数和返回值,只可以作为变量或者函数内的存储或者库函数的参数。

声明为 public 的 mapping,会自动创建 getter 函数。KeyType 作为参数,ValueType 作为返回值。

mapping 无法被遍历。不过有一些开源库用一种结构来实现了可遍历的 mapping。可以直接拿过来用。



相关文章
|
7月前
|
存储 供应链 安全
《Solidity 简易速速上手小册》第1章:Solidity 和智能合约简介(2024 最新版)
《Solidity 简易速速上手小册》第1章:Solidity 和智能合约简介(2024 最新版)
207 1
|
7月前
|
存储 安全 区块链
《Solidity 简易速速上手小册》第4章:智能合约的设计与开发(2024 最新版)
《Solidity 简易速速上手小册》第4章:智能合约的设计与开发(2024 最新版)
155 0
|
7月前
|
设计模式 监控 安全
《Solidity 简易速速上手小册》第5章:智能合约的安全性(2024 最新版)
《Solidity 简易速速上手小册》第5章:智能合约的安全性(2024 最新版)
141 1
|
存储 前端开发 JavaScript
区块链智能合约编程语言 Solidity
上文介绍了[区块链生态发展](https://wangbinguang.blog.csdn.net/article/details/131440404),我们知道以太坊的到来可以使开发人员基于区块链开发DApp,本文介绍 Solidity 编程语言的使用,然后基于 Solidity 编写一个简单的智能合约。
130 1
|
区块链
dapp互助公排智能合约系统开发指南与规则
智能合约作为区块链技术应用最广泛的场景之一
|
存储 前端开发 Unix
一文聊透 Solidity 语法:助你成为智能合约专家(二)
一文聊透 Solidity 语法:助你成为智能合约专家
108 0
|
开发框架 分布式计算 JavaScript
什么是NFT链游项目游戏系统开发技术(Demo)采用Solidity 智能合约系统开发方案
什么是NFT链游项目游戏系统开发技术(Demo)采用Solidity 智能合约系统开发方案
151 0
|
SQL 安全 API
热门区块链游戏指定系统开发技术讲解方案(Solidity)框架
热门区块链游戏指定系统开发技术讲解方案(Solidity)框架
343 0
|
存储 编译器 区块链
【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约 上
【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约
573 0
|
存储 JavaScript 前端开发
【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约 下
【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约
253 0
下一篇
DataWorks