V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
notot
V2EX  ›  Solidity

Solidity 入门教程 第一小节(主题有字数限制)

  •  
  •   notot · 2022-05-30 12:21:56 +08:00 · 1973 次点击
    这是一个创建于 890 天前的主题,其中的信息可能已经有所发展或是发生改变。

    导读

    此教程适合至少了解过一点合约相关知识,对区块链有基本共识同学进行观看。

    不管你是需要阅读合约源码,亦或是需要编写合约。这份指南都会对你有所帮助,这份为个人整理比不上官方文档,但是对特别需要注意的知识点做了补充说明,可用此文档进行过度。在后续有更加细节的知识点需要查询时,可到官方文档进行查阅。

    Official Solidity Docs - EN

    Community Solidity Docs - ZH

    01. Tutorial

    1.1 基础语法

    pragma solidity >=0.4.0 <0.6.0;
    contract SimpleStorage {
       uint storedData;
       function set(uint x) public {
          storedData = x;
       }
       function get() public view returns (uint) {
          return storedData;
       }
    }
    

    上面是一个最简单的合约

    Pragma

    第一行表示合约对应的 solidity 版本,大于等于 0.4.0 但是小于 0.6.0

    也可以像下面这种写法

    pragma solidity ^0.4.0;
    

    Contract

    合约本质上就是运行在区块链上的一段代码,如上方所示 unit storedData 代表了它是运行上区块链上的一个变量。我们可以通过下方的 get set 来对他进行修改。

    Import

    在 solidity 语言中,想要使用其他模块的方法或属性,则需要进行倒入,总共由两种方法

    import "filename"
    

    也可以使用

    import * as symbolName from "filename";
    

    1.2 第一个程序

    注意:solidity 不像 JS JAVA 等语言,可以直接在本地运行,它更多的是需要像 EVM 这样的环境才能运行,所以在刚开始练习的时候,最好是用比较简单,能直观看到结果的编辑器。

    打开页面 Remix IDE,运行我们的代码。

    Step 1

    将下方 Example 中的代码拷贝到 Remix 中

    Example

    pragma solidity ^0.5.0;
    contract SolidityTest {
       constructor() public{
       }
       function getResult() public view returns(uint){
          uint a = 1;
          uint b = 2;
          uint result = a + b;
          return result;
       }
    }
    

    Step 2

    切换到 编译 Tab ,点击编译

    image-20220524153016705

    Step 3

    点击部署

    image-20220524153348647

    Step 4

    部署完成之后,下方就可以看到我们部署后的合约

    image-20220524153639653

    然后将合约展开,展开之后我们就可以在这里面调用合约中代码。

    image-20220524153706691

    点击 getResult

    image-20220524153724296

    就能得到结果。这样我们就完成了第一个 solidity 程序的编写和部署测试。

    1.3 注释

    支持两种形式

    function getResult() public view returns(uint){
       // This is a comment. It is similar to comments in C++
    
       /*
          * This is a multi-line comment in solidity
          * It is very similar to comments in C Programming
       */
       uint a = 1;
       uint b = 2;
       uint result = a + b;
       return result;
    }
    

    1.4 类型

    types

    地址 Address

    address 保存代表以太坊地址大小的 20 字节值。 一个地址可以使用 .balance 方法获取余额,也可以使用 .transfer 方法将余额转移到另一个地址。

    address x = 0x212;
    address myAddress = this;
    if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
    

    image-20220527113057200

    address 这里容易让人有点误解,明明存入的是 0x1341243243... 这样的一个东西,但是却可以直接点出方法 balancetransfer这里需要消化一下,不然后面容易懵

    这里的 address 对象我们可以理解为是一个包装数据类型,可以直接理解 address 为一个类,他本身就具备很多方法。只不过在初始化的时候跟传统的 Struct 结构的数据不一样。只需要设置地址就可以了,程序会自动帮我们处理。

    address 中所有的可用方法

    <address>.balance (uint256):

    以 Wei 为单位的 地址类型 的余额。

    <address>.transfer(uint256 amount):

    地址类型 发送数量为 amount 的 Wei ,失败时抛出异常,发送 2300 gas 的矿工费,不可调节。

    <address>.send(uint256 amount) returns (bool):

    地址类型 发送数量为 amount 的 Wei ,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。

    <address>.call(...) returns (bool):

    发出低级函数 CALL,失败时返回 false,发送所有可用 gas ,可调节。

    <address>.callcode(...) returns (bool)

    发出低级函数 CALLCODE,失败时返回 false,发送所有可用 gas ,可调节。

    <address>.delegatecall(...) returns (bool):

    发出低级函数 DELEGATECALL,失败时返回 false,发送所有可用 gas ,可调节。

    1.5 变量

    image-20220524155201718

    此小节非常重要。

    在 Solidity 中总共有 3 种变量

    • 状态变量
    • 本地变量
    • 全局变量

    状态变量

    表明存储在合约中的变量,什么叫存储在合约中呢,其实就相当于 Java 里面的成员变量,在 solidity 中的写法如下

    pragma solidity ^0.5.0;
    contract SolidityTest {
       uint storedData;      // State variable
       constructor() public {
          storedData = 10;   // Using State variable
       }
    }
    

    本地变量

    其值仅在定义它的函数内可用的变量。 函数参数始终是该函数的本地参数。其实说白了就是局部变量,就是写在方法里面的。

    pragma solidity ^0.5.0;
    contract SolidityTest {
       uint storedData; // State variable
       constructor() public {
          storedData = 10;   
       }
       function getResult() public view returns(uint){
          uint a = 1; // local variable
          uint b = 2;
          uint result = a + b;
          return result; //access the local variable
       }
    }
    

    全局变量 [重要‼️]

    image-20220527113057200

    全局变量是存在于全局工作空间中的特殊变量,它们提供关于区块链和交易属性的信息。说白了就是不需要声明,有点类似于 Node 里面的 Process ,浏览器里面的 Windows ,可以直接拿来使用。

    Solidity 中的全局变量有下面几种。

    • block.blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希——仅可用于最新的 256 个区块且不包括当前区块;而 blocks 从 0.4.22 版本开始已经不推荐使用,由 blockhash(uint blockNumber) 代替
    • block.coinbase (address): 挖出当前区块的矿工地址
    • block.difficulty (uint): 当前区块难度
    • block.gaslimit (uint): 当前区块 gas 限额
    • block.number (uint): 当前区块号
    • block.timestamp (uint): 自 unix epoch 起始当前区块以秒计的时间戳
    • gasleft() returns (uint256):剩余的 gas
    • msg.data (bytes): 完整的 calldata
    • msg.gas (uint): 剩余 gas - 自 0.4.21 版本开始已经不推荐使用,由 gesleft() 代替
    • msg.sender (address): 消息发送者(当前调用)
    • msg.sig (bytes4): calldata 的前 4 字节(也就是函数标识符)
    • msg.value (uint): 随消息发送的 wei 的数量
    • now (uint): 目前区块时间戳(block.timestamp
    • tx.gasprice (uint): 交易的 gas 价格
    • tx.origin (address): 交易发起者(完全的调用链)

    看一下在合约中如何使用 全局变量

    pragma solidity ^0.5.0;
    contract SolidityTest {
    
       function getNowTime() public view returns(uint) {
           return now;
       }
    
       function getSender() public view returns (address payable) {
           return msg.sender;
       }
    
       function getGaslimit() public view returns (uint) {
           return block.gaslimit;
       }
    }
    

    然后在从新点击 部署,按照上面讲过的步骤

    image-20220524161629834

    然后运行部署后的合约。

    变量命名规范

    • 您不应使用任何 Solidity 保留关键字作为变量名。 这些关键字将在下一节中提到。 例如,break, bool 。

    • Solidity 变量名称不应以数字 (0-9) 开头。 它们必须以字母或下划线字符开头。 例如,123test 是一个无效的变量名,但 _123test 是一个有效的变量名。

    • Solidity 变量名称区分大小写。 例如,name 和 Name 是两个不同的变量。

    1.6 变量作用域

    在 1.5 小节中讲到 Solidity 中有三种类型的变量

    • 状态变量
    • 本地变量
    • 全局变量

    本地变量的作用于只存在于方法中,但是状态变量有三种作用域。

    • Public

      公共状态变量可以在内部访问,也可以通过消息访问。 对于公共状态变量,会生成一个自动 getter 函数。

    • Internal

      内部状态变量只能从当前合约或从它派生的合约内部访问,而不使用 this 。就类似于 Java 里面的 protected

    • Private

      私有状态变量只能在当前合约内部访问,它们不是在派生合约中定义的。

    • ? External

    pragma solidity ^0.5.0;
    contract C {
       uint public data = 30;
       uint internal iData= 10;
       
       function x() public returns (uint) {
          data = 3; // internal access
          return data;
       }
    }
    contract Caller {
       C c = new C();
       function f() public view returns (uint) {
          return c.data(); //external access
       }
    }
    contract D is C {
       function y() public returns (uint) {
          iData = 3; // internal access
          return iData;
       }
       function getResult() public view returns(uint){
          uint a = 1; // local variable
          uint b = 2;
          uint result = a + b;
          return storedData; //access the state variable
       }
    }
    

    上方 Example 的合约关系为

    • 定义了一个 合约 C ,并在合约 C 种定义了一个 public 状态变量和一个 interval 状态变量
    • 定义了一个合约 Caller ,并在内部 New 了合约 C
    • 定义了一个合约 D 并继承 C

    1.7 省略章节

    • 循环
    • if
    • 操作符
    • array
    • enum

    以上内容都比较常规,和平常使用的编程语言,语法差异不大。大家有兴趣可以查查官方文档,这里就不在赘述。

    1.8 struct

    struct struct_name { 
       type1 type_name_1;
       type2 type_name_2;
       type3 type_name_3;
    }
    

    struct 可以理解为多种类型的一个包装,就和包装数据类型是一样的。

    Eample

    pragma solidity ^0.5.0;
    
    contract test {
       struct Book { 
          string title;
          string author;
          uint book_id;
       }
       Book book;
    
       function setBook() public {
          book = Book('Learn Java', 'TP', 1);
       }
       function getBookId() public view returns (uint) {
          return book.book_id;
       }
    }
    

    1.9 Mapping

    mapping(_KeyType => _ValueType)

    • _KeyType: 可以是任何内置类型加上字节和字符串。不允许引用类型或复杂对象。
    • _ValueType: 任何类型都可以

    可以理解为 Hash 类型

    pragma solidity ^0.5.0;
    
    contract LedgerBalance {
       mapping(address => uint) public balances;
    
       function updateBalance(uint newBalance) public {
          balances[msg.sender] = newBalance;
       }
    }
    contract Updater {
       function updateBalance() public returns (uint) {
          LedgerBalance ledgerBalance = new LedgerBalance();
          ledgerBalance.updateBalance(10);
          return ledgerBalance.balances(address(this));
       }
    }
    
    1 条回复    2023-02-19 17:38:29 +08:00
    NK007
        1
    NK007  
       2023-02-19 17:38:29 +08:00
    牛的,不过我去 udemy 上面找课程了~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5620 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 01:33 · PVG 09:33 · LAX 17:33 · JFK 20:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.