美文网首页
SOL01:Solidity语言基础

SOL01:Solidity语言基础

作者: 杨强AT南京 | 来源:发表于2020-04-14 08:21 被阅读0次

      Solidity是传说中编写智能合约的脚本语言,运行在EVM中;用以解决区块链中的任务执行。一个目前看起来还非常稚嫩的语言。这里做一个结构性介绍。并据此展开详细的说明。


    Solidity语言特点

    • Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。
    • 这门语言受到了 C++,Python 和 Javascript 语言的影响,设计的目的是能在以太坊虚拟机(EVM)上运行。
    • Solidity 是静态类型语言,支持继承、库和复杂的用户定义类型等特性。
    • 使用Solidity 语言,可以为各种应用创建合约
      • 投票;
      • 众筹;
      • 秘密竞价(盲拍);
      • 多重签名的钱包;
      • 以及其他应用;

    Slidity语言结构

    源代码文件

    1. 源代码文件与其他语言一样,使用文本文件,扩展名使用sol。

    2. 文件的的组织操作系统的文件一样,使用目录组织;

      • 文件之间使用import引用,引用可以指定目录名。这个与ES6语法类似。
      • import "filename";
        • 此语句将从 “filename” 中导入所有的全局符号到当前全局作用域中。
      • import * as symbolName from "filename";
        • 创建一个新的全局符号 symbolName,其成员均来自 "filename" 中全局符号。
      • import {symbol1 as alias, symbol2} from "filename";
        • 创建新的全局符号 alias 和 symbol2,分别从 "filename" 引用 symbol1 和 symbol2 。
      • import "filename" as symbolName;
        • 条语句等同于 import * as symbolName from "filename";。

    目录

    • 支持"."与".."
      • ".":当前目录
      • "..":上级目录
    • 在编译器支持目录重映射:
      • import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
      • 编译:solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol

    文件结构

      • 版本申明
      • import
    1. 合约

      • contract 合同名 {}
    2. 注释

      • 与javascript一样,行注释与块注释。
      • //
      • /**/

    例子

    1. other.sol
    pragma solidity ^0.6.1;
    
    contract Other {
        uint value;
    }
    
    
    1. solidity.sol
    pragma solidity ^0.6.1;
    
    import "./other.sol";
    // 行注释
    contract MySol is Other {
        /**
        块注释
        */
        uint age;
    }
    
    
    1. 编译
      • solcjs --abi solidity.sol other.sol
    多文件编译

    合约contract

    • 在 Solidity 中,合约类似于面向对象编程语言中的类。 每个合约中可以包含

      1. 状态变量;
      2. 函数;
      3. 函数修饰器;
      4. 事件;
      5. 结构类型;
      6. 枚举类型 ;
    • 合约可以继承的

    合约定义

    
        contract 合约名 [is] 父合约{
            // 1. 状态变量;
            // 2. 函数;
            // 3. 事件;
            // 4. 结构类型;
            // 5. 枚举类型;
        }
    
    

    状态变量

    
        contract MyContract {
            uint varState; // 状态变量
            // ...
        }
    
    • 状态变量:
      • 类型 存储名;
      • 类型见后面说明;

    函数与函数修饰

    • 合约中可执行单元
    
    contract Purchase {
        address public seller;
    
        modifier onlySeller() { // 修饰器
            require(
                msg.sender == seller,
                "Only seller can call this."
            );
            _;
        }
    
        function abort() public onlySeller { // 函数与修饰器使用
            // ...
        }
    }
    

    事件

    • 事件是能方便地调用以太坊虚拟机日志功能的接口。
        contract SimpleAuction {
            
            event HighestBidIncreased(address bidder, uint amount); // 事件
    
            function bid() public payable {
                // ...
                emit HighestBidIncreased(msg.sender, msg.value); // 触发事件
            }
        }
    

    结构类型

    • 结构是可以将几个变量分组的自定义类型
      • 用户自定义复合类型
        contract Ballot {
            struct Voter { // 结构
                uint weight;
                bool voted;
                address delegate;
                uint vote;
            }
            // .....
        }
    

    枚举类型

    • 举可用来创建由一定数量的“常量值”构成的自定义类型.
        contract Purchase {
            enum State { Created, Locked, Inactive } // 枚举
        }
    

    合同继承

    • 使用is关键字实现。
        pragma solidity ^0.4.16;
    
        contract owned {
            function owned() { owner = msg.sender; }
            address owner;
        }
    
        // 使用 is 从另一个合约派生。派生合约可以访问所有非私有成员,包括内部函数和状态变量,
        // 但无法通过 this 来外部访问。
        contract mortal is owned {
            function kill() {
                if (msg.sender == owner) selfdestruct(owner);
            }
        }
    
    • 主要:
      • 继承包含抽象类与接口的定义。

    抽象合约

    • 语法没有什么差异,主要在函数的实现上:
      • 包含抽象函数 // 没有实现函数体的函数就是抽象函数
      • 抽象合约:
        • 主要是只有抽象函数的合约就是接口合约。
        • 实现函数与抽象函数混杂的就是抽象合约。
        contract Feline {    // 可以包含实现的就是抽象合约,这里只有一个抽象函数,实际也是接口合约。
            function utterance() public returns (bytes32);   
        }
        contract Cat is Feline {
            function utterance() public returns (bytes32) { return "miaow"; }
        }
    

    • 使用libarary定义库,定义好的库可以在合约中使用,下面是官方的例子:
      • 库的语法与合约差不多,合约可以使用库中数据与函数。
    pragma solidity ^0.4.16;
    
    library Set {
      // 我们定义了一个新的结构体数据类型,用于在调用合约中保存数据。
      struct Data { mapping(uint => bool) flags; }
    
      // 注意第一个参数是“storage reference”类型,因此在调用中参数传递的只是它的存储地址而不是内容。
      // 这是库函数的一个特性。如果该函数可以被视为对象的方法,则习惯称第一个参数为 `self` 。
      function insert(Data storage self, uint value)
          public
          returns (bool)
      {
          if (self.flags[value])
              return false; // 已经存在
          self.flags[value] = true;
          return true;
      }
    
      function remove(Data storage self, uint value)
          public
          returns (bool)
      {
          if (!self.flags[value])
              return false; // 不存在
          self.flags[value] = false;
          return true;
      }
    
      function contains(Data storage self, uint value)
          public
          view
          returns (bool)
      {
          return self.flags[value];
      }
    }
    
    contract C {
        Set.Data knownValues;
    
        function register(uint value) public {
            // 不需要库的特定实例就可以调用库函数,
            // 因为当前合约就是“instance”。
            require(Set.insert(knownValues, value));
        }
        // 如果我们愿意,我们也可以在这个合约中直接访问 knownValues.flags。
    }
    

    数据类型与数据

    数据的定义

    • 语法:

      • 类型 变量名 = 初始值
      • 变量名遵循Javascript的命名规则。
    • 删除变量

      • delete 变量名;
    • 常量:

      • constant:
      • int constant a = 2000;

    数据类型与字面值

    布尔类型与布尔值

    1. 类型关键字:bool
    2. 布尔值:truefalse

    整数类型与整数值

    1. 类型关键值:
      • int / uint (有符号与无符号)
      • 整数也分字节大小:单位是位,8位一个字节,根据对齐规则,必须是8的倍数。
        • int8/uint8
        • 。。。
        • int256/uint256 = int/uint
    2. 整数值:
      • 只支持10与16进制
        • 普通法表示:122
          • 不能前缀0。
          • 16进制使用hex前缀转换:hex"001122FF" 或者 0x前缀。
        • 科学记数法表示:1e10
          • 指数必须是整数,不支持小数。

    小数类型与小数值

    1. 小数类型关键字:fixed / ufixed

      • 有符号与无符号小数
      • 小数还可以自带精度表示:
        • ufixedMxN / fixedMxN (M表示表示该类型占用的位数,N表示可用的小数位数)
          • M也必须是8的倍数,最大256。
    2. 小数值:

      • 使用小数点表示小数。 与整数一样,分成普通表示与科学表示。
    3. 例子:

      • ufixed32x2 score = 12.45;
    4. 注意:

      • Solidity 还没有完全支持定长浮点型。可以声明定长浮点型的变量,但不能给它们赋值或把它们赋值给其他变量。。

    地址类型与地址值

    • 地址类型存储一个 20 字节的值(以太坊地址的大小)。
    • 地址类型也有成员变量,并作为所有合约的基础。
    1. 地址类型关键字:address
    2. 地址值表示:0x开头的16进制表示。
    3. 地址变量包含多个成员(成员属性与成员函数),用来访问地址相关信息:
      • balance :balance 属性来查询一个地址的余额
      • send/transfer :transfer 函数向一个地址发送 以太币Ether (以 wei 为单位):
    • 备注:地址的所有成员:
      1. <address>.balance (uint256):

        • 以Wei为单位的地址类型的余额。
      2. <address>.transfer(uint256 amount):

        • 向地址类型发送数量为amount的Wei,失败时抛出异常,发送 2300 gas 的矿工费,不可调节。
      3. <address>.send(uint256 amount) returns (bool):

        • 向地址类型 发送数量为 amount 的 Wei,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。
      4. <address>.call(...) returns (bool):

        • 发出低级函数 CALL,失败时返回 false,发送所有可用 gas,可调节。
      5. <address>.callcode(...) returns (bool)

        • 发出低级函数 CALLCODE,失败时返回 false,发送所有可用 gas,可调节。
      6. <address>.delegatecall(...) returns (bool):

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

    数组类型与值表示

    1. 数组关键字:类型[]
    2. 数组的创建:new
    3. 例子:
    
        pragma solidity ^0.4.16;
    
        contract C {
            function f(uint len) public pure {
                uint[] memory a = new uint[](7);
                a[6] = 8;
            }
        }
    
    1. 两个特殊的数组:
      • bytes 与 string 等加以 int8[]或者 byte[]
    2. 例子:
        pragma solidity ^0.4.16;
    
        contract C {
            function f(uint len) public pure {
                uint[]  a = new uint[](7);
                bytes  b = new bytes(len);   // string b= new string(len)
                // 这里我们有 a.length == 7 以及 b.length == len
                a[6] = 8;
            }
        }
    
    1. 数组字面值

      • [1, 2, 3, 4]
    2. 数组变量赋值的注意事项:长度一致

      • 下面例子无法赋值:
    // 这段代码并不能编译。
    
    pragma solidity ^0.4.0;
    
    contract C {
        function f() public {
            // 这一行引发了一个类型错误,因为 unint[3] memory
            // 不能转换成 uint[] memory。
            uint[] x = [uint(1), 3, 4];
        }
    }
    
    1. 数组的成员

      • length属性:获取数组长度,还可以通过这个成员属性修改数组的长度(只对存储有效,为位置在内存的变量无效,参考后面存储位置的说明)
      • push函数:用来向数组末尾添加数据
      • 这length对字符串数组无效。
    2. 多维数组:

      • bool[2][3] m_pairsOfFlags;

    字符串类型与值表示

    1. 字符串也是数组,其字面值表示:

      • "foo":3字节字符数组。
      • 字符串数组与bytes数组可以隐式转换。
    2. 字符串支持转移字符

      • 字符串字面常数支持转义字符,例如 \n,\xNN 和 \uNNNN\xNN 表示一个 16 进制值,最终转换成合适的字节, 而 \uNNNN 表示 Unicode 编码值,最终会转换为 UTF-8 的序列。

    枚举类型

    1. 定义枚举类型

      • enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
    2. 使用枚举类型

      • ActionChoices defaultChoice = ActionChoices.GoStraight;
    pragma solidity ^0.4.16;
    
    contract test {
        enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
        ActionChoices choice;
        ActionChoices constant defaultChoice = ActionChoices.GoStraight;
    
        function setGoStraight() public {
            choice = ActionChoices.GoStraight;
        }
    

    结构体

    • 结构体是定义新的类型,语法如下:
    
        struct Funder {
            address addr;
            uint amount;
        }
    
    
    
    • 结构体不能包含自己。

    存储位置

    • 所有的复杂类型,即数组和结构类型,都有一个额外属性,“数据位置”,

      1. 说明数据是保存在 内存memory 中还是 存储storage 中。
      2. 根据上下文不同,大多数时候数据有默认的位置,但也可以通过在类型名后增加关键字 storage 或 memory 进行修改。
      3. 函数参数(包括返回的参数)的数据位置默认是 memory, 局部变量的数据位置默认是 storage,状态变量的数据位置强制是 storage 。
    • 第三种数据位置calldata

      1. 这是一块只读的,且不会永久存储的位置,用来存储函数参数。
      2. 外部函数的参数(非返回参数)的数据位置被强制指定为 calldata ,效果跟 memory 差不多。
    • 例子:

    pragma solidity ^0.4.0;
    
    contract C {
        uint[] x; // x 的数据存储位置是 storage
    
        // memoryArray 的数据存储位置是 memory
        function f(uint[] memoryArray) public {
            x = memoryArray; // 将整个数组拷贝到 storage 中,可行
            var y = x;  // 分配一个指针(其中 y 的数据存储位置是 storage),可行
            y[7]; // 返回第 8 个元素,可行
            y.length = 2; // 通过 y 修改 x,可行
            delete x; // 清除数组,同时修改 y,可行
            // 下面的就不可行了;需要在 storage 中创建新的未命名的临时数组, /
            // 但 storage 是“静态”分配的:
            // y = memoryArray;
            // 下面这一行也不可行,因为这会“重置”指针,
            // 但并没有可以让它指向的合适的存储位置。
            // delete y;
    
            g(x); // 调用 g 函数,同时移交对 x 的引用
            h(x); // 调用 h 函数,同时在 memory 中创建一个独立的临时拷贝
        }
    
        function g(uint[] storage storageArray) internal {}
        function h(uint[] memoryArray) public {}
    }
    

    映射(key - value)

    • 映射类型在声明语法为

      • mapping(_KeyType => _ValueType)
      • 其中 _KeyType 可以是除了映射、变长数组、合约、枚举以及结构体以外的几乎所有类型。
      • _ValueType 可以是包括映射类型在内的任何类型。
    • 映射可以视作哈希表

      • 它们在实际的初始化过程中创建每个可能的 key, 并将其映射到字节形式全是零的值:一个类型的 默认值。
      • 然而下面是映射与哈希表不同的地方:
        • 在映射中,实际上并不存储 key,而是存储它的keccak256哈希值,从而便于查询实际的值。

    类型转换

    • 类型转换一般分成显式转换与隐式转换:
      • 显式转换 : 类型(值)

    运算符与表达式

    布尔运算

    1. ! (逻辑非)
    2. && (逻辑与, "and" )
    3. || (逻辑或, "or" )
    4. == (等于)
    5. != (不等于)

    整数运算

    1. 比较运算符:
      • <= , < , == , != , >= , > (返回布尔值)
    2. 位运算符:
      • & , | , ^ (异或), ~ (位取反)
    3. 算数运算符:
      • + , - , 一元运算 - , 一元运算 + , * , / , % (取余) , ** (幂), << (左移位) , >> (右移位)

    小数运算

    1. 比较运算符:
      • <=, <, ==, !=, >=, > (返回值是布尔型)
    2. 算术运算符:
      • +, -, 一元运算 -, 一元运算 +, *, /, % (取余数)

    地址运算

    • 比较运算:
      • <=, <, ==, !=, >= 和 >

    数组运算

    1. 比较运算符:
      • <=, <, ==, !=, >=, > (返回布尔型)
    2. 位运算符:
      • &, |, ^ (按位异或), ~ (按位取反), << (左移位), >> (右移位)
    3. 索引访问:
      • 如果 x 是 bytesI 类型,那么 x[k] (其中 0 <= k < I)返回第 k 个字节(只读)。
    4. .length
      • 表示这个字节数组的长度(对定长只读).

    流程控制

    1. JavaScript 中的大部分控制结构在 Solidity 中都是可用的,除了 switch 和 goto。

      • if,else,
      • while,
      • do,
      • for,
      • break,continue,return,
      • ? :
    2. 注意:

      • 用于表示条件的括号不可以被省略,单语句体两边的花括号可以被省略。
      • 与C和JavaScript不同, Solidity 中非布尔类型数值不能转换为布尔类型,因此 if (1) { ... } 的写法在 Solidity 中 无效 。

    相关文章

      网友评论

          本文标题:SOL01:Solidity语言基础

          本文链接:https://www.haomeiwen.com/subject/rqwamhtx.html