官⽹:http://solidity.readthedocs.io/en/develop/
Solidity是⼀个⾯向对象的⾼级语⾔,其语法是类JavaScript,是运⾏在以太坊虚拟机中的代码,它是静态类型的编程语⾔。

版本申明

pragma solidity ^0.4.0;

^0.4.0代表solidity编译器的版本号,第⼆位的4是主版本,第三位的4是
⼩版本,^符号表示版本向上兼容,即 0.4.4 ~ 0.5.0(不包含0.5.0) 之间的solidity均可编译该合约代码,⼀般修
复bug时会更新⼩版本,⼤调整时修改主版本

全局引⼊

import “filename”

⾃定义命名空间引⼊

import * as symbolName from “filename”

全局引入案例
hello.sol 先进行部署

pragma solidity ^0.4.21;

contract Test{
    string str1;
    
    function setValue (string para) public {
        str1 = para;
    }
    
    function getValue() constant public returns (string){
        return str1;
    }
}

importTest.sol 再进行部署 参数填写之前合约的地址,”str” 会修改第一个合约的数值

pragma solidity ^0.4.20;

import "./hello.sol";

contract ImportTest {

    function setString (Test test, string str) public {
        test.setValue(str);
    }
}

合约的结构(基本组成元素)
每个合约中可包含状态变量(State Variables),函数(Functions),函数修饰符(Function Modifiers),事件
(Events),结构类型(Structs Types)和枚举类型(Enum Types)
合约类似于⾯向对象语⾔中的 类 ,且 ⽀持继承

状态变量(State Variables)
变量值会永久存储在合约的存储空间

pragma solidity ^0.4.0;

// simple store example
contract simpleStorage{
  uint valueStore; //state variable
}

函数(Functions)
智能合约中的⼀个可执⾏单元

pragma solidity ^0.4.0;
contract simpleMath{
//Simple add function,try a divide action?
function add(uint x, uint y) returns (uint z){
z = x + y;
}
}

上述代码实现了⼀个简单的加法函数。合约函数的调⽤分为 内部调⽤internal 和 外部调⽤external ,后续函
数章节会详细介绍。

函数修饰符(Function Modifiers)

pragma solidity ^0.4.22;

contract Purchase {
    address public seller;
    
    modifier onlySeller() { // Modifier
        require(
            msg.sender == seller,
            "Only seller can call this."
        );
        _;
    }

    function abort() public onlySeller { // Modifier usage
        // ...
    }
}

事件(Events)
事件是以太坊虚拟机(EVM)⽇志基础设施提供的⼀个便利接⼝,⽤于⽇志输出,便于跟踪调试

pragma solidity ^0.4.21;
contract SimpleAuction {
    event HighestBidIncreased(address bidder, uint amount); // Event
    function bid() public payable {
        // ...
        emit HighestBidIncreased(msg.sender, msg.value); // Triggering event
    }
}

———————————————————————————————————————-

002.数据类型
值传递与引用传递
值传递 memory(Value Type) 引用传递 storage(Refernce Type) 将改变变量的值 类似于& 红色部分如果改为memory(默认)将不改变_name的值  如果改为 storage 引用传递 函数类型应改为private 在函数内部进行调取

pragma solidity ^0.4.20;

contract Student{
    string _name = "lily";
    uint _num;
    function execute() public{
        changeName(_name);
    }

    function changeName(string storage name) private{
        _num = 10;
        bytes(name)[0] = "L";
    }

    function getName() constant public returns (string) {
        return _name;
    }

    function getNum() constant public returns (uint){
        return _num;
    }
 }

 //memory(Value Type) storage(Refernce Type)

003.布尔类型

pragma solidity ^0.4.20;

contract BoolTest {
    uint v1 = 10;
    uint v2 = 20;
    string s1 = "hello";
    string s2 = "world";
    
    boo flag1 = true;
    bool flag2 = false;
    
    
    function f1() constant public returns (bool) {
        return !flag1;
    } 
    
     function f2() constant public returns (bool) {
        return flag1 && flag2;
    } 
    
    function f3() constant public returns (bool) {
        return flag1 || flag2;
    } 
    
    function f4() constant public returns (bool) {
        return v1 == v2;
    } 
    
    function f5() constant public returns (bool) {
        return v1 != v2;
    } 
}

004.整型

pragma solidity ^0.4.21;

contract IntegerTest {
    
    /*
    
    //&,|,^(异或),~(位取反)
    10  uint8    1010     
    4   uint8    0100
    
    &            0000      0
    |            1110     14
    ^            1110     14
    
    ~   3  0000,0011  1100     12 
           1111,1100   
           1111,1111 - 3
           2^8 -1 -3 = 256 -4 = 252
    */
    
    uint8 a = 10;
    uint8 b = 4;
    uint8 c = 3;
    
    function f1() constant public returns (bool) {
        return  a & b == 0;
    }
    
    function f2() constant public returns (bool) {
        return  a | b == 14;
    }
    
    function f3() constant public returns (bool) {
        return  a ^ b == 14;
    }
    
    function f4() constant public returns (bool) {
        return  (~c) == 252;
    }
    
    function f5() constant public returns (uint8){
        return ~c;
    }  

}

地址(Address)

以太坊地址的⻓度,⼤⼩ 20个字节 , 160位 ,所以可以⽤⼀个 uint160 编码。地址是所有合约的基础,所有
的合约都会继承地址对象,也可以随时将⼀个地址串,得到对应的代码进⾏调⽤。
⽀持的运算符:
描述 符号
⽐较运算符 <=,<,==,!=,>=,>

地址类型的成员:
属性: balance
⽅法: send() , transfer() , call() , delegatecall() , callcode()

地址与整型转换

pragma solidity ^0.4.20;


contract AddressTest {
    address _add1 = 0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db;
    address _add2 = 0x583031d1113ad414f02576bd6afabfb302140225;

    //加public会有一个匿名函数方便展示
    uint160 public _num = 0;
    address public _add;

    function address2uint160() public returns(uint160){
        _num = uint160(_add1);
        return _num;
    }
    
    
    function uint160ToAddress() public returns(address){
        _add = address(_num);
        return _add;
    }
    
    function comAddress() constant public returns(bool){
        return _add1 == _add2;
    }
    
    function isGreater() constant public returns(bool){
        return _add1 > _add2;
    }
}

balance余额

pragma solidity ^0.4.20;

contract addressBalance {

    function getBalance(address addr) constant public returns (uint){
        return addr.balance;
    }
}

sender消息发起人

pragma solidity ^0.4.20;


contract senderTest {
    address public _owner; //存储合约创建者地址
    
    // 构造函数
    function senderTest() public {
        _owner = msg.sender; // 是合约创建者地址 只执行一次
    }
    
    function getOwnerBalance() public returns (uint256){
        return msg.sender.balance; // 每一个sender发送者的钱包地址 地址会变动
    }
    
    function getInvoker() constant public returns (address){
        return msg.sender; // 每一个sender发送者的余额 地址会变动
    }
}

this获取合约信息及地址

表示智能合约的地址的变量: this指针
如果只是想返回当前合约账户的余额,可以使⽤ this 指针, this 表示合约⾃身的地址

对于合约来说,地址代表的就是合约本身,合约对象默认继承⾃地址对象,所以内部有地址的属性。
注:this和msg.sender不⼀样, this代表的是合约本身的地址,msg.sendr返回的是请求合约的账户的地址

pragma solidity ^0.4.20;


contract addressThis {
    
    uint _money;
    // 构造函数
    function addressThis() payable public { //payable 表示这个合约可以接受钱了
        _money = msg.value; //合约部署时value字段 给的金额
    }
    
    function getThis() constant public returns (address){
        return this; //返回合约本身
    }
    
    function getBalance () constant public returns (uint256){
        return this.balance; //合约余额
    }
    
    function getMoney() constant public returns(uint){
        return _money;
    }
    
    function getMsgSender() constant public returns (address){
        return msg.sender; //请求发送者地址 变化的
    }
}

转账transfer介绍

pragma solidity ^0.4.20;

//在测试网测试通过合约进行转账
//注意value字段在部署合约的时候不要写 当合约部署完成后 调取转账函数时再填写value字段

//acc2 : 8.9     0x794C3fF2068455dbeb5D5D039347d221d10C905f

//Alice : 12.9   0xa446742e4845CFbA8EC7d93226eE6ceB6C7C91ab

contract TransferTest {
    
    address AliceAddress = 0xa446742e4845CFbA8EC7d93226eE6ceB6C7C91ab;
    
    function transfer() payable { //为了避免误操作 转账函数必须含有payable关键字才可以
        AliceAddress.transfer(msg.value);
    }
}

转账send()函数

这两个⽅法都是⽤来发送货币的,使⽤的参数也都⼀致。不同之处在于:合约运⾏出错或由于gas耗尽⽽停
⽌时, transfer() ⽅法会抛出异常,⽽ send() ⽅法相对于 transfer() ⽽⾔更底层,它不抛异常,⽽是会
返回false。
注:send() 执⾏有⼀些⻛险:如果调⽤栈的深度超过1024或gas耗光,交易都会失败。因此,为了保证安
全,必须检查send的返回值,如果交易失败,会回退以太币。如果⽤transfer会更好。

pragma solidity ^0.4.20;


//acc8 : 6.9     0xa7eEEAC067530608Ed24E76c47A57d1b35702cce

//Alice : 11.9   0xa446742e4845CFbA8EC7d93226eE6ceB6C7C91ab

//注意value字段在部署合约的时候不要写 当合约部署完成后 调取转账函数时再填写value字段

contract TranferTest {
    
    address AliceAddress = 0xa446742e4845CFbA8EC7d93226eE6ceB6C7C91ab;
    bool res;
    function transfer() payable public returns (bool){
        //send()方法转账更底层与transfer用法一样 但是send方法使用处理不当会有风险
        res = AliceAddress.send(msg.value);
        return res;
    }
}

006.枚举类型
枚举类型是在Solidity中的⼀种⽤户⾃定义类型。他可以显示的转换与整数进⾏转换,但不能进⾏隐式转
换。显示的转换会在运⾏时检查数值范围,如果不匹配,将会引起异常。枚举类型应⾄少有⼀名成员,枚举
元素默认为uint8,当元素数量⾜够多时,会⾃动变为uint16,第⼀个元素默认为0,使⽤超出范围的数值时
会报错。

pragma solidity ^0.4.0;

contract enumTest {
    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } //uint8  顺序 0 1 2 3
    ActionChoices _choice;
    ActionChoices  defaultChoice = ActionChoices.GoStraight;

    //设置 0 1 2 3 
    function setGoStraight(ActionChoices choice) public {
        _choice = choice;
    }

    //读取 0 1 2 3 数字
    function getChoice() constant public returns (ActionChoices)  {
        return _choice;
    }

    //返回2
    function getDefaultChoice() constant public returns (uint) {
        return uint(defaultChoice);
    }
    
    //输入0返回true
    function isGoLeft(ActionChoices choice) constant public returns (bool){
        if (choice == ActionChoices.GoLeft){
            return true;
        }
        
        return false;
    }
}

007.函数类型 内部外部类型函数

pragma solidity ^0.4.5;

contract FuntionTest{
    uint public v1;
    uint public v2;
   
   /*  uint public v1 就类似于下面这个函数 在部署时可以查看变量数值
    function v1() constant returns (uint) {
        return v1;
    }
    */
    
    // 只能在合约内部调取 外部合约无法调用
    function internalFunc() internal{
        v1 = 10;
    }

    function externalFunc() external returns (uint res){
        v2 = 20;
        return v2;
    }

    function resetV2() public {
        v2 = 0;
    }

    function callFunc() {
        //直接使用内部的方式调用
        internalFunc();  //<--- 合约内部直接调用,正确

        //不能在内部调用一个外部函数,会报编译错误。
        //Error: Undeclared identifier.
        //externalFunc(); //<--- 外部合约可以调用

        //不能通过`external`的方式调用一个`internal`
        //Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
        //this.internalFunc();  //<--- this相当于外部调用

        //使用`this`以`external`的方式调用一个外部函数
        this.externalFunc();
    }
}

// 继承 FuntionTest 所有方法 可以用internal 不可以用external
contract Son is FuntionTest {
    function callInternalFunc()  public{
        internalFunc();
        //externalFunc(); 无法调取外部函数
    }
}


contract FunctionTest1{
    uint public v3;
    function externalCall(FuntionTest ft){ //FuntionTest ft 参数 输入第一个合约部署的合约地址
        //调用另一个合约的外部函数
        v3 = ft.externalFunc(); //得到20 将改变v3结果

        //不能调用另一个合约的内部函数
        //Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
        //ft.internalFunc();
    }

    function resetV3() public {
        v3 = 0;
    }
}

008.数组
1. 定⻓数组bytes1 … bytes32
字节不可修改
⻓度不可修改
⽀持 length (只读)
⽀持下标索引

pragma solidity ^0.4.0;
contract C {
    bytes10 public b = "helloworld";
    uint public len;
    function f() public {
        len = b.length;
        //b.length = 10; //ERROR,⻓度为只读,不可修改
    }
    bytes1 public c = b[0];
    //b = "HELLO";ERROR,定义之后不可修改
}

byte[n]
引⽤类型
⽀持下标
⻓度可不变
可以修改

pragma solidity ^0.4.4;
contract C {
    bytes9 bb = 0xabcde;
    byte[9] aa = [byte(0x6c),0x69,0x79,0x75,0x65,0x63,0x68,0x75,0x6e];
    byte[8] cc = [byte("a"), "b"];
    uint len = aa.length;
    function test() public{
        aa[0] = 0xa1;
        //bb[0] = 0xa1;
    }
}

不定⻓数组
内容和⻓度均可修改,包括以下三种: 类型[⻓度] 、 bytes 、 string
第⼀种:类型[⻓度]
动态数组
可以修改
可以改变⻓度(storage)
⽀持 length 、 push ⽅法
可使⽤new关键字创建⼀个memory的数组。与stroage数组不同的是,你不能通过.length的⻓度来修改数组
⼤⼩属性。我们来看看下⾯的例⼦:

pragma solidity ^0.4.0;
contract C {
function f() {
    //创建⼀个memory的数组
    uint[] memory a = new uint[](7);
    //不能修改⻓度
    //Error: Expression has to be an lvalue.
    //a.length = 100;
    for (uint i = 0; i< a.length; i++){
        a[i] = i;
    }
    //a.push(10);
    }
    //storage
    uint[] public b;
    function g(){
        b = new uint[](7);
        //可以修改storage的数组
        b.length = 10;
        b[9] = 100;
        b.push(101);
    }
}

直接创建
* 内容可变
* ⻓度不可变
* ⽀持length⽅法,不⽀持push

pragma solidity ^0.4.5;
contract test {
    uint [10] value = [1,2,3,4,5];
    uint public sum;
    function getSum(){
        sum = 0;
        for (uint i = 0; i < value.length; i++){
        sum += value[i];
    }
    }
    function changeValue(){
        value[0] = 2;
    }
}

第⼆种:bytes 动态字节数组
引⽤类型
⽀持 下标索引
⽀持 length 、 push ⽅法
可以修改

pragma solidity ^0.4.4;
contract C {
    bytes public _name = new bytes(1);
    bytes public _name2;
    function setLength(uint length) {
        _name.length = length;
    }
    function getLength() constant returns (uint) {
        return _name.length;
    }
    function setName(bytes name){
        _name = name;
    }
    function changeName(bytes1 name){
        _name[0] = name;
    }
    function setInside(){
        _name = "helloWorld";
        _name2 = "HELLOWORLD2";
    }
}

第三种:string
动态尺⼨的UTF-8编码字符串,是特殊的可变字节数组
引⽤类型
不⽀持下标索引
不⽀持 length 、 push ⽅法
可以修改(需通过bytes转换)
注:bytes和string可以⾃由转换
string转换成bytes

pragma solidity ^0.4.4;
contract C {
    string public _name = "lily";
    function nameBytes() constant returns (bytes) {
        return bytes(_name);
    }
    function nameLength() constant returns (uint) {
        return bytes(_name).length;
    }
    function changeName() public {
        bytes(_name)[0] = "L";
        //s2[0] = "H"; //ERROR,不⽀持下标索引
    }
    function changeLength() {
        bytes(_name).length = 15;
        bytes(_name)[14] = "x";
    }
}

各种数组转换关系图:

pragma solidity ^0.4.20;


contract Test {
    
    bytes10 b10 = 0x68656c6c6f776f726c64;     //helloworld 文本转为16进制
    
    bytes public bs10 = new bytes(b10.length);
    
    //1. 固定字节数组转动态字节数组
    function fixedBytesToBytes() public{
        for (uint i = 0; i< b10.length; i++){
            bs10[i] = b10[i];
        }
    }
    
    
    //2、字符串转为bytes
    string  greeting = "helloworld";
    bytes public b1;
    function StringToBytes() public {
        b1 = bytes(greeting);
    }
    
    //3.string转动态字节数组
    string public str3;
    function BytesToString() public {
        str3 = string(bs10);
    }
}

009.结构体

pragma solidity ^0.4.5;

contract Test {
    struct Student {
        string name;
        uint age;
        uint score;
        string sex;
    }

    Student public stu1 = Student("lily",18,90,"girl");
    Student public stu2 = Student({name:"jim",age:20,score:80,sex:"boy"});

    Student[] public Students;

    function assign() public {
            Students.push(stu1);
            Students.push(stu2);

            stu1.name = "Lily";
    }
}

010.映射/字典 (mapping)

键的类型允许除映射外的所有类型,如数组,合约,枚举,结构体。值的类型⽆限制。
creates a namespace in which all possible keys exist, and values are initialized to 0/false.
所以⽆法判断⼀个mapping中是否包含某个key,因为它认为每⼀个都存在,只不过是0或false
映射可以被视作为⼀个哈希表,其中所有可能的键已被虚拟化的创建,被映射到⼀个默认值(⼆进制表示的
零)。在映射表中,我们并不存储键的数据,仅仅存储它的 keccak256 哈希值,⽤来查找值时使⽤。
映射类型,仅能⽤来定义状态变量,或者是在内部函数中作为storage类型的引⽤

pragma solidity ^0.4.20;

contract test {
    // id -> name
    mapping(uint => string) id_names;

    constructor() public {
        id_names[0x001] = "lily";
        id_names[0x002] = "Jim";
        id_names[0x002] = "mike";
    }

    function getNameById(uint id) constant public returns (string){
        string storage name = id_names[id];
        return name;
    }
}

11.⾃动推导类型
为了⽅便,并不总是需要明确指定⼀个变量的类型,编译器会通过第⼀个向这个对象赋予的值的类型来进⾏
推断

uint24 x = 0x123;
var y = x;

函数的参数,包括返回参数,不可以使⽤var这种不指定类型的⽅式。
需要特别注意的是,由于类型推断是根据第⼀个变量进⾏的赋值。所以下⾯的代码将是⼀个⽆限循环,,因
为⼀个uint8的i的将⼩于2000。

for (var i = 0; i < 2000; i++)
{
//⽆限循环
}

演示

pragma solidity ^0.4.4;
    contract Test{
    function a() returns (uint){
        uint count = 0;
        for (var i = 0; i < 257; i++) { count++; if(count >= 258){
                break;
            }
        }
        return count;
    }
}

12.全局函数
将如下代码使用remix在metamask进行部署,并且与合约进行交互调取 tt()方法进行查看 如果遇到GAS不足错误提示 增大GAS费用 (增大“燃料限制”数字)

pragma solidity ^0.4.21;


contract Test {
    
    bytes32 public _blockhash;
    address public coinbase;
    uint public difficulty;
    uint public gaslimit;
    uint public blockNum;
    uint public timestamp;
    bytes public calldata;
    uint public gas;
    address public sender;
    bytes4 public sig;
    uint public msgValue;
    uint public _now;
    uint public gasPrice;
    address public txOrigin;
    
    function tt () payable public {
        //给定区块号的哈希值,只支持最近256个区块,且不包含当前区块
        _blockhash = blockhash(block.number - 1);
        coinbase = block.coinbase ;//当前块矿工的地址。
        difficulty = block.difficulty;//当前块的难度。
        gaslimit = block.gaslimit;// (uint)当前块的gaslimit。
        blockNum = block.number;// (uint)当前区块的块号。
        timestamp = block.timestamp;// (uint)当前块的时间戳。
        calldata = msg.data;// (bytes)完整的调用数据(calldata)。
        gas = gasleft();// (uint)当前还剩的gas。
        sender = msg.sender; // (address)当前调用发起人的地址。
        sig = msg.sig;// (bytes4)调用数据的前四个字节(函数标识符)。
        msgValue = msg.value;// (uint)这个消息所附带的货币量,单位为wei。
        _now = now;// (uint)当前块的时间戳,等同于block.timestamp
        gasPrice = tx.gasprice;// (uint) 交易的gas价格。
        txOrigin = tx.origin;// (address)交易的发送者(完整的调用链)  
    }

}

13.货币单位与时间单位介绍

pragma solidity ^0.4.0;

contract EthUnit{
    uint  a = 1 ether;
    uint  b = 10 ** 18 wei;
    uint  c = 1000 finney;
    uint  d = 1000000 szabo;

    function f1() constant public returns (bool){
        return a == b;
    }

    function f2() constant public returns (bool){
        return a == c;
    }

    function f3() constant public returns (bool){
        return a == d;
    }

    function f4() pure public returns (bool){
        return 1 ether == 100 wei;
    }
}



contract TimeUnit{

    function f1() pure public returns (bool) {
        return 1 == 1 seconds;
    }

    function f2() pure public returns (bool) {
        return 1 minutes == 60 seconds;
    }

    function f3() pure public returns (bool) {
        return 1 hours == 60 minutes;
    }

    function f4() pure public returns (bool) {
        return 1 days == 24 hours;
    }

    function f5() pure public returns (bool) {
        return 1 weeks == 7 days;
    }

    function f6() pure public returns (bool) {
        return 1 years == 365 days;
    }
}

constant、view、pure介绍

pragma solidity ^0.4.20;


contract Test {
    
    //一、constant介绍
    uint public v1 = 10;
    uint constant v2 = 10;
    
    string str1 = "hello!";
    string constant str2 = "test!";
    
    function f1() public {
        v1  = 20;
        //v2 = 30;  //constant修饰的值类型无法被修改
        
        str1 = "Hello!"; 
       // str2 = "Test!";
    }
    
    struct Person {
        string name;
        uint age;
    }
    
    
    //错误的 -> Person constant p1;  //constant仅可以修饰值类型,无法修饰引用类型(string除外)


    function f2() constant public{
        v1 = 20; //constant 修饰的函数内,如果修改了状态变量,那么状态变量的值是无法改变的,小心!!
        
    }
    
    //二、view介绍
    // 1. view只可以修饰函数
    // 2. 它表明该函数内尽可以对storage类型的变量进行读取,无法修改
    
    
    //三、pure介绍
    //pure
    // 1. pure只可以修饰函数
    // 2. 它表明该函数内,无法读写状态变量
    function f3() pure public returns(uint){
        //return v1; 读写都错误
    }
}

15.错误处理
传统⽅法:采⽤ throw 和 if … throw 模式(已过时)
例如合约中有⼀些功能,只能被授权为 拥有者 的地址才能调⽤。

新⽅法:
新函数 require() , assert() , revert() 提供了同样功能,⽽且上下⽂更加⼲净。

下⾯的代码:
if(msg.sender != owner) { throw; }

等价于:
if(msg.sender != owner) { revert(); }
assert(msg.sender == owner);
require(msg.sender == owner);
注意在 assert() 和 require() 例⼦中的条件声明,是 if 例⼦中条件块取反,也就是⽤ == 代替了 != 。

pragma solidity ^0.4.21;

contract HasAnOwner {
    address public owner;
    uint public a ;
    
    constructor() public {
        owner = msg.sender;
    }
    
    function useSuperPowers()  public { 
        require(msg.sender == owner);
        /* 等同于 如果发送者不是创建合约者会抛出异常
        if (msg.sender != owner){
            throw;
        }
        */
        
        a = 10;
       // do something only the owner should be allowed to do
    }
}

16.delete介绍
delete操作符可以⽤于任何变量,将其设置成默认值
如果对动态数组使⽤delete,则删除所有元素,其⻓度变为0
如果对静态数组使⽤delete,则重置所有索引的值
如果对map类型使⽤delete,什么都不会发⽣
指定键删除:但如果对map类型中的⼀个键使⽤delete,则会删除与该键相关的值

pragma solidity ^0.4.21;

contract deleteTest {
    string public str1 = "hello";
    
    //delete操作符可以用于任何变量(mapping除外),将其设置成默认值
    function delStr() public{
        delete str1;
    }
    
    function setStr() public {
        str1 = "HELLO";
    }
    
    //静态数组,动态数组
    uint[10] public staticArray = [4,2,4,5,6,7,8];
    uint[] public dynamicArray = new uint[](10);
    
    function intDynamicArray () public {
        for (uint i = 0; i< 10; i++) { //dynamicArray[i] = i; dynamicArray.push(i); } } //如果对静态数组使用delete,则重置所有索引的值 function delStaticArray() public { delete staticArray; } //如果对动态数组使用delete,则删除所有元素,其长度变为0 function delDynamicArray() public { delete dynamicArray; } function getArrayLength() view public returns (uint, uint){ return (staticArray.length, dynamicArray.length); } mapping(uint => bool) public map1;
    
    function initMap() public {
        map1[1] = true;
        map1[2] = true;
        map1[3] = false;
        
        //delete map1;
    }
    
    function deleMapByKey(uint key) public {
        delete map1[key];
    }
    //delete map1;
    
    struct Person {
        string name;
        mapping(string => uint) nameScore;
    }
    
    Person public p1;
    
    function initP1() public {
        p1.name = "duke";
        p1.nameScore["duke"] = 80;
    }
    
    function returnP1() view public returns (string, uint) {
        return (p1.name, p1.nameScore["duke"]);
    }
    
    function deleteP1() public {
        delete p1;
    }
}

17.modifier修饰器介绍
修改器(Modifiers)可以⽤来轻易的改变⼀个函数的⾏为。⽐如⽤于在函数执⾏前检查某种前置条件。修改器
是⼀种合约属性,可被继承,同时还可被派⽣的合约重写(override)。下⾯我们来看⼀段示例代码:

本代码在运行useSuperPowers()函数时先运行ownerOnly() 修饰器条件校验 校验成功后 _;代码回换为 a = 10; 要执行的代码 直接执行 否则将失败

pragma solidity ^0.4.21;

contract HasAnOwner {
    address public owner;
    uint public a ;
    
    constructor() public {
        owner = msg.sender;
    }
    
    modifier ownerOnly(address addr) {
        require(addr == owner);
        //代码修饰器所修饰函数的代码
        _;
    }
    
    
    function useSuperPowers() ownerOnly(msg.sender) public { 
        a = 10;
       // do something only the owner should be allowed to do
    }
}

继承
Solidity通过复制包括多态的代码来⽀持多重继承。
所有函数调⽤是虚拟(virtual)的,这意味着最远的派⽣⽅式会被调⽤,除⾮明确指定了合约。
当⼀个合约从多个其它合约那⾥继承,在区块链上仅会创建⼀个合约,在⽗合约⾥的代码会复制来形成继承
合约。

表达式和控制结构不⽀持switch和goto,⽀持if,else,while,do,for,break,continue,return,?: