深入理解Solidity

Solidity源文件布局

pragma(版本杂注)

  • 用于指定源文件的版本,表明编译器的版本,例如 pragma solidity ^0.4.0
  • ^用于指代版本号需要大于0.4.0但是不可以超过大的层级,必须小于0.5.0
  • 也可以使用大于等于小于来指定版本

import(导入其它源文件)

  • Solidity所支持的导入语句import,语法和JavaScript非常类似
  • import “filename”;  从“filenmae”中导入所有的全局富豪到当前的全局作用域中
  • import * as symbolName from “filename”;  创建一个新的全局符号symbolName,其成员均来自于“filename”中的全局符号
  • import {symbol1 as alias ,symbol2} from "filename"; 创建新的全局符号alias和symbol2,分别从“fikename'”引用symbol1和symbol2
  • import “filename” as symbolName;这条语句等同于import * as symbolName from “filename”; 

Solidity值类型

  • 布尔(bool)可能的结果为字符常量值true或者false
  • 整型(int/uint)分别表示有符号和无符号的不同位数的整型变量,支持关键字uint8到uint256(无符号,从8位到256位)以及int8到int256,每8位为一个步长进行递增
  • 定长浮点型(fixed/ufixed):表示各种大小的有符号的无符号的定长浮点型,在关键字ufixedMxN和fixedMxN中,M表示该类型占用的位数,N表示可用的小数的位数,这个必须要小于80
  • 地址(address)存储一个20字节的值(以太坊的地址的大小)
  • 定长字节数组:关键字有bytes1、bytes2、bytes3,。。。,bytes32,如果没有数字bytes就是不定长的
  • 枚举(enum)一种用户可以定义类型的方法,与C语言类似,默认从0开始递增,一般用于模拟合约的状态
  • 函数(function)一种表示函数的类型

Solidity引用类型

数组(Array)

  • 数组可以在声明的时候指定长度(定长数组),也可以动态调整大小(变长数组/动态数组)
  • 对于存储型(storage)的数组来说,元素的类型可以是任意的(即元素可以是数组类型、映射类型或者结构体)
  • 对于内存型(memory)的数组来说,元素的类型不能是映射(mapping)类型

结构(Struct)

  • Solidity 支持通过构造结构体的形式来定义新的类型

映射(Mapping)

  • 映射可以看作哈希表,在实际的初始化过程中创建每一个可能的key,并且将其映射到字节形式全是0的值(类型默认值)

Solidity地址类型

address

  • 地址类型存储一个20字节的值(以太坊地址的大小),地址的类型也有成员变量,并作为所有合约的基础

address payable(V0.5.0引入)

  • 与地址类型基本相同,不过多出了transfer和send;两个成员变量

两者的区别和转换

  • Payable地址是可以发送ether的地址,普通的address是不可以的
  • 允许从payable address到address的隐式转换,而反过来的直接转换是不可能的(唯一的方法是通过uint160来进行中间转换)
  • 从0.5.0版本起,合约不再是从地址类型派生而来,但是如果它有payable回退函数,那同样可以显示转换为address或者addresspayable类型

具体

  • <address>.balance(uint256) 该地址的ether余额,以Wei为单位
  • <address payable>.transfer(uint256 amount) 向指定地址发送数量为amount的ether(以Wei为单位),失败时抛出异常,发送23000gas的矿工费,不可以调节
  • <address payable>.send(uint256 amount)returns(bool)向指定地址发送数量为amount的ether(以Wei为单位),失败时返回false,发送23000gas的矿工费,不可以调节
  • <address>.call(bytes memory)returns (bool,bytes memory) 发出底层函数CALL,失败时候返回false,发送所有可用的gas,可以调节
  • <address>.delegatecall(bytes memory)returns (bool,bytes memory)发出底层函数DELEGATECALL,失败时候返回false,发送所有可用的gas,可以调节
  • <address>.staticcall(bytes memory) returns(bool,bytes memory)发出底层函数STATICCALL,失败时候返回false,发送所有可用的gas,可以调节

用法

balance和transfer

  • 可以使用一个balance属性来查询一个地址的余额,可以使用tranafer函数像一个payable地址发送以太币Ether(以wei为单位)
address payable x = address(0x123);
address myaddress = address(this);
if(x.balance < 10 && myaddress.balance >= 10)
x.transfer(10);
  • 哪个地址调用transfer函数,就向哪个地址转钱。以太坊的水管合约,发起交易实质是香我们的账户打钱

send

  • send是transfer的初级版本。如果执行失败,当前的合约不会因为异常而终止,但是send会返回false

call

  • 通过添加call来实现转币操作,通过添加.gas()和.value()装饰器
nameReg.call.gas(1000000).value(1 ether)(abi.encodeWithSignature("register(string)","MyName"));

字符数组(Byte Arrays)

定长字符数组

  • 属于值类型,bytes1、bytes2,。。。,bytes32分别代表了长度1到32的字节序列

  • 有一个.length属性,返回数组的长度(只读)

变长字符数组

  • 属于引用类型,包括bytes和string,不同的是bytes是Hex字符串,而string是UTF-8编码的字符串

数组

  • 固定大小k和元素类型T的数组被写成T[k],动态大小的数组为T[]。例,一个由5个uint动态数组组成的数组是uint[][5],和C语言不一样,固定大小写在数组的第二个[]里面
  • 要访问第三个动态数组中的第二个uint,可以使用x[2][1]
  • 越界访问数组,会导致调用失败回退
  • 如果要添加新的元素,则必须受用.push()或者将.length增大
  • 变长的storage数组和bytes(不包括string)有一个push()方法。可以将一个新的元素附加到数组的末端,返回值为当前的数组长度
  • 例子
pragma solidity >=0.4.16 <0.6.0
contract C{
    function f(uint len)public pure{
        uint[] memory a = new uint[](7);
        bytes memory b = new bytes(len);
        assert(a.length == 7);
        assert(b.length == len);
        a[6] = 8;
    }
}

枚举

  • 枚举类型用来用户自定义一组常量值
  • 和C语言类似,对应整型值,从0开始累加
pragma solidity >=0.4.0 <0.6.0;
contract Purchase{
    enum Weekday {Monday,Thusday,Wednesday}

    function test() public pure returns(uint16){
        Weekday wd = Weekday.Wednesday;
        return uint16(wd);//2
    }
}

结构

  • 结构体可以在映射和数组中使用,他们本身可以包含映射和数组
  • 结构不能包含自己类型的成员,但是可以作为自己数组成员的类型,也可以作为自己映射成员的值类型
pragma solidity >=0.4.0 <0.6.0
contract Ballot{
    struct Voter{
        uint weight;
        bool voted;
        uint vote;
   }
}

映射(Mapping)

  • 声明一个映射 mapping(_KeyType => _ValueType)
  • _KeyType可以是任何基本类型,这意味着它可以是任何内置值类型加上字符数组和字符串。不可以使用用户定义的或者复杂的类型,如枚举、映射、结构以及除了bytes和string之外任何数组类型。投票合约的时候,使用地址映射一个结构体,可以使用简单结构来映射复杂结构,不可以使用复杂结构来映射简单结构。本质上类似key-value的形式,使用简单的结构来查询复杂结构,但是不可以通过复杂结构来查询简单结构。
  • _ValueType可以是任何类型,包括映射

例子

  • 合约D调用合约C
pragma solidity ^0.4.0;
contract C{
    mapping (address => uint)balances;
    
    constructor(){
        balances[address(this)] = 300;
    }

    function updata(uint amount)public{
        balances[msg.sender] = amount;
    }

    function getBalance(address _addr)public returns (uint){
        return balances[_addr];
    }
}

contract D{
    function fun() public returns(uint){
        C c = new C();//调用C合约
        c.update(10);//将C合约的复制了一份到D合约,将其改成了10
        return c.getBalance(address(c));//C合约的仍然是300
        return c.getBalance(address(this));//this指代当前合约D,合约是10
        return c.getBalance(msg.sender);//部署合约的地址,因此是0
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【技术背景】区块链,是一个分布式的共享账本和数据库,具有去中心化、不可篡改、可追溯、公开透明等特点。区块链技术作为科技创新的代表和未来技术的发展方向,已经上升至国家战略高度。它将为解决信息不对称问题、创造信任与合作机制等提供丰富的应用空间,也会是未来我们技术自主创新、引领产业变革的重要突破口。比特币被认为是区块链技术1.0版的应用,主要实现的是电子现金的分布式记账转账功能。而随着技术的不断发展更新,越来越多的人希望突破“账本”的限制,从而可以把这项未来技术应用在更广阔的领域。以太坊(Ethereum)为代表的第二代区块链公链项目,就是其中的佼佼者。与比特币不同,以太坊的定位是一个“世界计算机”。以区块链作为底层存储技术,我们不仅可以记账转账,而且可以构建“智能合约”(smart contract)定义程序化的处理流程,进而实现区块链上运行的“去中心化应用”(DApp)。以太坊项目自提出后就受到了广泛关注,快速的发展和壮大,而且由于其“分布式应用平台”而非“分布式账本”的定位,越来越多的开发人员开始以以太坊为基础设施,在上面开发DApp。随着更多开发人员的参与,和项目的逐步落地,以太坊已成为从事区块链学习和开发不可或缺的一个环节;既了解区块链底层原理、又熟悉以太坊架构、还能基于以太坊开发DApp的专业人才,也成为了各大公司发力区块链技术储备的重点对象。【课程简介】本套以太坊课程,对以太坊基础理论知识和架构做了系统的梳理和深入的阐述,并对solidity和DApp的开发做了系统讲解,另外还对以太坊白皮书、黄皮书做了介绍;为有志于学习区块链技术、了解以太坊底层架构和DApp开发原理的工程师提供学习平台和帮助。本教程内容主要分为五大部分:以太坊基础、以太坊原理和架构、以太坊编程及应用、合约工作流以及原理深入分析。通过学习本套课程,可以使学习者对以太坊有充分的认识,对整个区块链技术有更深刻的理解,对区块链应用开发有更加整体的领悟。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值