WEB3系列教程之新手篇--level6:Solidity

原文地址: https://www.learnweb3.io/tracks/freshman/solidity

翻译: JulySong

什么是 Solidity?

  • Solidity 是一种面向对象的高级语言,用于实现智能合约。它旨在针对以太坊虚拟机(EVM)
  • 它是静态类型的,支持继承、库和复杂的用户声明类型等特性。

构建 Solidity

初始化智能合约

1
2
3
4
5
6
7
// Define the compiler version you would be using
pragma solidity ^0.8.10;

// Start by creating a contract named HelloWorld
contract HelloWorld {

}

变量和类型

Solidity 中有 3 种类型的变量

  • Local
    • 在函数内部声明并且不存储在区块链上
  • State
    • 在维护智能合约状态的函数之外声明
    • 存储在区块链上
  • Global
    • 提供有关区块链的信息。它们在运行时由以太坊虚拟机注入。
    • 包括交易发送者、区块时间戳、区块哈希等。
    • 全局变量示例

变量的范围是由它们的声明位置声明的,而不是它们的值。将局部变量的值设置为全局变量不会使其成为全局变量,因为它仍然只能在其范围内访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 定义您将使用的编译器版本
pragma solidity ^0.8.10;

// 首先创建一个名为 Variables的合约
contract Variables {
/*
******** State 变量 **********
*/
/*
使用uint代表无符号整数, 表示不同大小的非负整数可用. 例如:
- uint8 范围 从 0 到 2 ** 8 - 1
- uint256 范围 从 0 到 2 ** 256 - 1
`public` 表示该变量可以被合约内部访问,也可以被外部世界读取
*/
uint8 public u8 = 10;
uint public u256 = 600;
uint public u = 1230; // uint is an alias for uint256

/*
该int类型允许为负数. 例如:
- int256 ranges from -2 ** 255 to 2 ** 255 - 1
*/
int public i = -123; // int 相当于 int256

// address 代表了一个以太坊地址
address public addr = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;

// bool 代表了 boolean类型
bool public defaultBoo1 = false;

// 默认值
// 在Solidity中未赋值的变量有一个默认值
bool public defaultBoo2; // false
uint public defaultUint; // 0
int public defaultInt; // 0
address public defaultAddr; // 0x0000000000000000000000000000000000000000

function doSomething() public {
/*
******** Local 变量 **********
*/
uint ui = 456;

/*
******** Global 变量 **********
*/

/*
block.timestamp 告诉我们当前块的时间戳是什么
msg.sender 告诉我们哪个地址调用了 doSomething 函数
*/
uint timestamp = block.timestamp; // 当前区块时间戳
address sender = msg.sender; // 调用者地址
}
}

函数、循环和 If/Else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 声明您将使用的编译器版本
pragma solidity ^0.8.10;

// 首先创建一个合同叫Conditions
contract Conditions {
// 声明一个State变量来存储数字
uint public num;

/*
函数的名称是 set.
需要在使用uint和num设置state变量。
该方法声明为public 类型表示它也可以从内部被称为合同和外部。
*/
function set(uint _num) public {
num = _num;
}

/*
函数的名称是 get。
该方法的返回值为数字
该方法声明为view 类型表示函数不改变任何变量的状态。
在solidity中view函数不消耗汽油.
*/
function get() public view returns (uint) {
return num;
}

/*
函数名是 foo。
该方法需要一个unit参数, 并且返回一个unit参数。
该方法通过if/else来比较入参x的大小
*/
function foo(uint x) public returns (uint) {
if (x < 10) {
return 0;
} else if (x < 20) {
return 1;
} else {
return 2;
}
}

/*
函数的名称是循环。
它运行一个循环直到 10
*/
function loop() public {
// for 循环
for (uint i = 0; i < 10; i++) {
if (i == 3) {
// 用continue跳到下一个迭代
continue;
}
if (i == 5) {
// 用break跳出循环
break;
}
}
}


}

数组、字符串

数组可以具有编译时固定大小或动态大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
pragma solidity ^0.8.10;

contract Array {

// 声明一个public字符串变量
string public greet = "Hello World!";
// 初始化数组的几种方式
// 这里初始化的数组被认为是存储在区块链上的状态变量
// 以下就是存储变量
uint[] public arr;
uint[] public arr2 = [1, 2, 3];
// 固定大小的数组,初始化所有元素为0
uint[10] public myFixedSizeArr;
/*
函数的名称是 get
它获取存储在数组索引中的元素的值
*/
function get(uint i) public view returns (uint) {
return arr[i];
}

/*
Solidity 可以返回整个数组。
这个函数被调用并返回一个 uint[] 内存。
内存 - 该值仅存储在内存中,而不是在区块链上,
它仅在函数执行期间存在

Memory变量和Storage变量可以被认为类似于 RAM 与硬盘。
Memory变量在函数执行期间暂时存在,而Storage变量
在合约生命周期内跨函数调用保持不变。
这里数组仅在函数执行期间需要,因此被声明为Memory变量
*/
function getArr(uint[] memory _arr) public view returns (uint[] memory) {
return _arr;
}

/*
此函数返回字符串内存。
添加 memory 关键字的原因是因为 string 在内部作为数组工作
这里字符串仅在函数执行时才需要。
*/
function foo() public returns (string memory) {
return "C";
}

function doStuff(uint i) public {
// 追加到数组
// 这将使数组长度增加 1.
arr.push(i);
// 从数组中删除最后一个元素
// 这将使数组长度减少 1
arr.pop();
// 获取数组的长度
uint length = arr.length;
// 删除不会改变数组长度。
// 它将 index 处的值重置为其默认值,
// 在这种情况下,它将 arr2 中索引 1 处的值重置为 0
uint index = 1;
delete arr2[index];
// 在内存中创建数组,只能创建固定大小
uint[] memory a = new uint[](5);
// 在内存中创建字符串
string memory hi = "hi";
}

}

参考

其他学习资源


练习题

  1. 🤔 Solidity 在哪个虚拟机上运行?

    A: JVM

    B: EVM

    C: KVM

  2. 🤔 Solidity 中的 State 变量是什么?

    A: 它们在函数内声明,不存储在区块链上

    B: 它们在函数外部声明并存储在区块链上

    C: 他们提供有关区块链的信息

  3. 🤔 uint 代表什么?

    A: 大学情报

    B: 普遍审讯

    C: 通用整数

    D: 无符号整数

  4. 🤔 uint8 的范围是多少?

    A: 0 到 2 ** 256 - 1

    B: 0 到 2 ** 16 - 1

    C: 0 到 2 ** 8 - 1

  5. 🤔 bool 变量的默认值是多少?

    A: True

    B: False

  6. 🤔 地址变量的默认值是多少?

    A: 0x0936f87C98E8009f8C4fff9E3994b295761C30ad

    B: 0x00000000000000000000000000000000000000000

    C: 0xD9cd57AaECf5813FC41E26CFd55f67Fd72112b75

  7. 🤔 函数声明中 public 关键字的意义是什么?

    A: 函数只能被其他智能合约函数内部调用

    B: 函数只能在外部调用

    C: 它可以从合约内部调用,也可以从外部调用。

  8. 🤔 函数声明中 view 关键字的意义是什么?

    A: 这意味着该函数可以改变合约的状态

    B: 函数不能改变合约的状态

    C: 它让任意方法不消耗汽油

  9. 🤔 从函数返回无符号整数数组的正确函数声明是什么?

    A: function getArr(uint[] memory _arr) public view returns (uint[] memory)

    B: function getArr(uint[] memory _arr) public view returns (uint[])

    C: function getArr(uint[] memory _arr) public view returns ([]uint)

  10. 🤔 如何在 Solidity 中获取数组的长度?

    A: len(arr)

    A: arr.length

    A: arr.size()

  11. 🤔 如何在 Solidity 中向数组中添加元素?

    A: arr.push(i)

    A: arr.add(i)

    A: arr.back(i)

  12. 🤔 msg.sender 是什么?

    A: 调用者地址

    B: 一个函数名

    C: 给你发短信的人的电话号码

  13. 🤔 block.coinbase 的值是什么?

    A: Coinbase 交易所地址

    B: 开采该区块的矿工的地址

    C: 当前区块的 gas 价格

参考答案:

  1. B
  2. B
  3. D
  4. C
  5. B
  6. B
  7. C
  8. B
  9. A
  10. B
  11. A
  12. A
  13. B