{"content":{"title":"Solidity学习笔记一：基础语法与remix的使用","body":"---\r\ntheme: nico\r\nhighlight: a11y-dark\r\n---\r\n\r\n本人是一只前端程序猿，最近各种前端已死的言论甚嚣尘上，既然web2走不通了，那就去web3这条赛道瞧瞧\r\n\r\n参加了登链社区技术集训营二期，又看了其他的教学视频，感觉是越学越迷糊\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/jBp9U4tn64e31e8ca3831.png)\r\n\r\n于是准备再学一遍，进行总结。如有错误，还请指正🫰希望各位大佬能够不吝赐教\r\n\r\n\r\n> **Solidity**：是一门面向合约的、为实现智能合约而创建的高级编程语言。\r\n> \r\n> **智能合约**：是管理以太坊状态里账户行为的程序。\r\n\r\nSolidity 是静态类型语言，支持继承、库和复杂的用户定义类型等特性。\r\n\r\n# 1、 从编辑器开始\r\n万事开头难，我们先拿编辑器开个头\r\n\r\n编写Solidity有很多种方式，我们先用浏览器的在线编辑器，比较简单，访问这个在线编辑器网站\r\n[Remix 编辑器](https://remix.ethereum.org/)\r\n\r\n第一步就是先把其他的文件给删除掉，\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/BE1oJAlV64e31b8c0fc58.png)\r\n\r\n第二步：新建自己的contracts文件夹 ，然后在里面新建一个以 `.sol` 结尾的文件\r\n（智能合约的文件都是以.sol结尾的）\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/KffWYgzA64e31b984d638.png)\r\n\r\n# 2、运行起来\r\n\r\n代码要先指明 solidity 使用的版本\r\n```js\r\npragma solidity 0.8.7; // 只是用这个版本\r\n```\r\nsolidity版本也有几种不同的声明方式\r\n\r\n```js\r\npragma solidity 0.8.7; // 只是用这个版本\r\n\r\npragma solidity ^0.8.7; // 比0.8.7这个版本更新的都适用\r\n\r\npragma solidity >0.8.7; // 大于这个版本\r\npragma solidity >=0.8.7 <0.9.0; // 大于等于这个版本适用  0.9以上的不适用\r\n```\r\n> 重点： 每行代码都要使用 `;` 结尾\r\n\r\n\r\n你以为 `pragma solidity 0.8.7;` 就是web3的第一行代码了吗？\r\n\r\nno ! no ! no ! no ! no !\r\n\r\n**在开始写程序之前 需要先声明一下，否则在有的编辑环境下有可能会报错**\r\n\r\n它是定义一个代码规则和分享规则\r\n\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.7;\r\n```\r\n在编辑器里，你写的代码就是这个样式\r\n\r\n然后进行编译，点击`Compile ...`是进行编译；没有语法错误编译成功时，1处就会有个绿色的对号\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/v2I57OvR64e31bb694bdb.png)\r\n\r\n到这 已经把 `Solidity` 项目运行起来了，虽然好像什么都没有，但是确实 实实在在的编译成功了\r\n\r\n接下来咱们继续，开始深入\r\n\r\n# 3、合约内容\r\n\r\n俗话说：万事开头难，然后中间难；现在开始学习智能合约，开始填充合约内容\r\n\r\n合约是使用 `contract` 进行声明的\r\n\r\n它就像一个java语言的class一样，**声明一个合约名**\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.7;\r\n\r\ncontract HelloWorld{\r\n// 合约内容\r\n}\r\n```\r\n\r\n## 数据类型\r\n在Solidity中的变量类型大概分为这几类\r\n1.  **数值类型(Value Type)** ：包括布尔型，整数型等等，这类变量赋值时候直接传递数值。\r\n\r\n\r\n2.  **引用类型(Reference Type)** ：包括数组和结构体，这类变量占空间大，赋值时候直接传递地址（类似指针）。\r\n3.  **映射类型(Mapping Type)** : `Solidity`里的哈希表。\r\n\r\n### 数值类型\r\n\r\n**数值类型** 最基础的有四种数据类型分别是 boolean , uint , int , address 等等\r\n> boolean  // 布尔值类型 默认值为false\r\n\r\n> int // 可表示正数和负数 默认值为0\r\n\r\n> uint // uint是无符号整数 表示这个数字不是可正可负的，就只能表示正数 默认值为0\r\n\r\n> string // 表示一个单词，字符串，需要用 “”\r\n\r\n> address // 表示地址 比如数字钱包的地址 默认值为0的地址： 0x0000000000000000000000000000000000000000\r\n\r\n> enum //枚举 \r\n\r\n#### boolean\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n    // 定义一个变量名为 hasFavoriteNumber 的布尔值\r\n    bool hasFavoriteNumber = true;\r\n}\r\n```\r\n#### uint\r\nuint是无符号整数 表示这个数字是正整数\r\n\r\n而且 solidity里也没有小数\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n    // 定义一个变量名为 favoriteNumber 的正数\r\n    uint favoriteNumber; // 初始化值为0\r\n    uint favoriteNumber1 = 666;\r\n    \r\n    // 我们可以给unit分配空间 uint8表示他有8个bit，uint就相当于uint256\r\n    uint8 favoriteNumber = 255;\r\n    uint favoriteNumber = 666; // 默认分配的空间大小就是256\r\n    uint256 favoriteNumber = 666; \r\n}\r\n```\r\n\r\n 但是如果我给 unit8 赋值一个比较大的数字，那么就会报错\r\n \r\n 因为赋值的数字已经超过了`unit8`可以存储的范围\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/UDmVOsOD64e31c1dd1d27.png)\r\n\r\n#### enum 枚举\r\n枚举（`enum`）是`solidity`中用户定义的数据类型。它主要用于为`uint`分配名称，使程序易于阅读和维护,使用名称来代替从`0`开始的`uint`：\r\n```js\r\n// 用enum将uint 0， 1， 2表示为Buy, Hold, Sell  \r\nenum ActionSet { Buy, Hold, Sell }  \r\n// 创建enum变量 action  \r\nActionSet action = ActionSet.Buy;\r\n```\r\n\r\n####  int\r\n可表示正数和负数 默认值为0\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n    // int\r\n    int favoriteInt = -5; \r\n    \r\n    int256 favoriteNumber = 666;\r\n}\r\n```\r\n#### string\r\n表示一个字符串\r\n\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n    // string类型\r\n    string favoriteText = \"dong\";\r\n}\r\n```\r\n\r\n#### address\r\n表示地址 比如数字钱包的地址\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n     // address类型\r\n    address myAddress = 0xb2028c070948d7F42FB1e0465dcB70F0671A155d;\r\n}\r\n```\r\n\r\n#### bytes\r\n\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n     // bytes类型 也可以制定大小  它通常存储以 0x开头后面跟一些随机数字和字母\r\n    bytes32 favoriteBytes = 0x3f89\r\n    // bytes 赋值字符串类型 会自动转化为bytes  32是它允许分配的最多的空间\r\n    bytes32 favoriteBytes = \"cat\"\r\n}\r\n```\r\n\r\n#### 定义一个常量\r\n**常量：** 在变量名前面 加上 **constant** 标识 , 常量名用大写字母表示\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.8;\r\n\r\ncontract HelloWorld {\r\n  address public constant MY_ADDRESS;\r\n   \r\n}\r\n```\r\n\r\n细心的同学可以发现，定义变量的时候在变量名前面有一个 `public`\r\n\r\n> **public** :表示这个变量公开了，任何与合约交互的人 都可以看到 变量中存储的值\r\n\r\n我们定义两个变量，一个带有public,一个不带，接下来我们把它部署一下\r\n```js\r\n// SPDX-License-Identifier: MIT \r\npragma solidity ^0.8.7;\r\n\r\n// 第一个合约\r\ncontract SimpleStorage {\r\n    uint myNumber = 111;\r\n    uint public favoriteNumber = 666;\r\n}\r\n```\r\n编译好后，我们点击 1 这个时候就进入编译的页面，按钮2:\"Deploy\" 就是部署\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/A7iBAW4B64e31c372da74.png)\r\n\r\n点击 Deploy 按钮 就会发现部署好后的操作区域，可以看到有public的显示在页面上，我们能看到，没有public标识的就没有公开\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/vzozty6P64e31c45b784c.png)\r\n\r\n接下来点击一下它就能看到它的值\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/9A57UZDx64e31c588a64c.png)\r\n\r\n\r\n## **引用类型**\r\n **引用类型(Reference Type)** ：包括数组和结构体，这类变量占空间大，赋值时候直接传递地址（类似指针）。\r\n\r\n### 数组\r\n数组： 如果你想建立一个集合，可以用 `数组` 这样的数据类型. Solidity 支持两种数组: 静态数组和 动态数组:\r\n```js\r\n// 固定长度为2的 uint类型的静态数组:\r\nuint[2] fixedArray;\r\n// 固定长度为5的 string类型的 静态数组:\r\nstring[5] stringArray;\r\n// 动态数组，长度不固定，可以动态添加元素:\r\nuint[] dynamicArray;\r\n```\r\n### 结构体\r\n`struct` 结构体：支持通过构造结构体的形式定义新的类型；声明一个自定义的类型\r\n```js\r\n// 结构体  \r\nstruct Student{  \r\n    uint256 id;  \r\n    uint256 score;  \r\n}\r\nStudent student; // 初始一个student结构体\r\n```\r\n\r\n以下是对数组和结构体的总结\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.18;\r\n\r\ncontract MyContract{\r\n    // 定义一个类型，类型名为People\r\n    struct People{\r\n        uint256 favoriteNumber;\r\n        string name;\r\n    }\r\n    // \r\n    People public people=People({favoriteNumber:6,name:'dong'});\r\n    People public people1=People({favoriteNumber:61,name:'dong1'});\r\n\r\n  // 定义一个数组\r\n    People[] public peopleList;\r\n    // 向数组内添加数据\r\n    function addPerson(string memory _name,uint256 _favoriteNumber) public{\r\n      \t// 添加数据方式一\r\n        People memory newPerson = People({favoriteNumber:_favoriteNumber, name:_name});\r\n        peopleList.push(newPerson);\r\n\r\n        // 方式二\r\n        peopleList.push(People({favoriteNumber:_favoriteNumber, name:_name}));\r\n    }\r\n}\r\n```\r\n\r\n## 函数\r\n`Solidity`里的函数我觉得和JS的函数非常相似，他也是用function关键字声明的，但是多了一些修饰符\r\n\r\n- function 函数名（参数）修饰符 {}\r\n\r\n参数也需要声明类型\r\n\r\n\r\n```js\r\n// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.18;\r\n\r\ncontract SimpleStorage {\r\n    uint256 public favoriteNumber; // 以0初始化变量\r\n\r\n    // 定义一个 store的函数 传入一个形参 \r\n    function store(uint256 _favoriteNumber) public {\r\n        // 进行赋值\r\n        favoriteNumber = _favoriteNumber;\r\n    }\r\n}\r\n```\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/LNBgswJF64e31c79671ea.png)\r\n点击黄色的 Deploy进行部署合约，就会出现以下信息\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/gTbDWsQj64e31c9255cd7.png)\r\n\r\n部署合约就 是发送一个交易;区块链上做任何事情，修改任何状态 就是在发一个交易, 我们可以在 store 里输入一个数字，然后点击 store按钮，就会调用一次合约会消耗一些gas\r\n\r\n在变量名`favoriteNumber`前面添加一个 **public** 表示这个变量公开了，可以在外部访问到它,我们看看能不能赋值成功\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2023/08/qbfm7W9064e31ca560be9.png)\r\n点击favoriteNumber 可以看到已经赋值成功\r\n\r\n### **函数和变量有 4 种可见度的标识符：**\r\n   - `public`表示公开，任何与合约交互的人 都可以看到 变量中存储的值（public会创建变量的getter函数，返回函数值）\r\n\r\n\r\n   - `private`表示只对合约内部可见；只能从本合约内部访问，继承的合约也不能用（也可用于修饰状态变量）。\r\n```js\r\nuint[] numbers;\r\n\r\nfunction _addToArray(uint _number) private {\r\n  numbers.push(_number);\r\n}\r\n```\r\n\r\n   - `external`表示只对合约外部可见；只能从合约外部访问（但是可以用`this.fn()`来调用，`fn`是函数名）\r\n\r\n   - `internal`表示只有这个合约或者继承它的合约可以读取；只能从合约内部访问，继承的合约可以用（也可用于修饰状态变量）。\r\n\r\n### 函数权限/功能 关键字\r\n\r\n - `payable`（可支付的）很好理解，带着它的函数，运行的时候可以给合约转入`ETH`\r\n\r\n- `view` 表示这个函数只会读取这个合约的状态，view函数里面不允许修改任何状态\r\n\r\n- `pure` 也不允许修改状态，而且pure也不允许读取区块链数据，不能读取变量;通常用于某个不需要读取数据的算法\r\n\r\n> **合约里面的操作和计算越多，消耗的gas也越多**\r\n\r\n\r\n\r\n### 函数输出\r\n`Solidity`的函数输出需要有两个关键字：`return`和`returns`\r\n\r\n-   `returns`加在函数名后面，用于声明返回的变量类型及变量名；\r\n-   `return`用于函数主体中，返回指定的变量。\r\n\r\n```js\r\n    // 返回多个变量\r\n    function returnMultiple() public pure returns(uint256, bool, uint256[3] memory){\r\n            return(1, true, [uint256(1),2,5]);\r\n        }\r\n```\r\n\r\n#### 命名式返回\r\n在 `returns` 里表明返回的变量名称，`solidity`会自动初始化这些变量，并返回这些函数的值；并且不需要使用 `return`\r\n\r\n```js\r\n    // 命名式返回\r\n    function returnNamed() public pure returns(uint256 _number, bool _bool, \r\n    uint256[3] memory _array){\r\n        _number = 2;\r\n        _bool = false; \r\n        _array = [uint256(3),2,1];\r\n    }\r\n````\r\n\r\n\r\n# 英语\r\n\r\n|英文 | 翻译 |\r\n|:-----------:|:-----------:|\r\n| Compile | 编绎;编译文件;编译 | \r\n| contract | 合同;合约;契约; | \r\n| private | 私有的;私人的;私用的; | \r\n| external | 外部的;外面的;外界的; | \r\n| internal | 里面的;体内的; |"},"author":{"user":"https://learnblockchain.cn/people/12067","address":"0x94b1ff90ec16e10b57e2f92b3bF5Fc9863Bc8EFE"},"history":null,"timestamp":1692607682,"version":1}