第四章 附部分solidity语法

solidity语法

第一部分 基本语法

智能合约中的变量结构

1.状态变量State Variables

永久储存在合约的存储中。

contract SimpleStorage {

uint storedData; // State variable

// ...

}

2.函数Functions

contract SimpleAuction {

function bid() payable { // Function

// ...

}

}

函数调用时,分为内部调用和外部调用(internal和external)

内部调用:不建立一个EVM调用(也就是message

call)

外部调用:建立一个EVM调用

注:状态变量和函数有四种可见性,external、public、internal和private。对于函数来说,默认是public;对于状态变量,external是不可能的,默认是internal。

external:可以通过其他合约或者交易外部调用。但是不可以内部调用,比如f()不可调用,但可以通过this.f()调用。接收大数组数据时,external效率会更高。

public:内部调用或者外部调用都可以。public的状态变量会自动生成访问函数(get/set)

internal:当前合约和源于它的合约(就是继承它的合约)可调用。

private:只在定义变量或函数的合约中可见。只是让区块链内部不可见,但是对于外界,仍然是可见的……

3.Modifier

modifier是以声明的方式,修改函数语句。

contract Purchase {

address public seller;

modifier onlySeller() { // Modifier

if (msg.sender != seller) throw;

_;

}

function abort() onlySeller { // Modifierusage

// ...

}

}

4.event

EVM日志记录工具的快捷接口

contract SimpleAuction {

event HighestBidIncreased(address bidder,uint amount); // Event

function bid() payable {

// ...

HighestBidIncreased(msg.sender, msg.value);// Triggering event

}

}

5.Structs结构体

contract Ballot {

struct Voter { // Struct

uint weight;

bool voted;

address delegate;

uint vote;

}

}

6.Enum枚举类型

contract Purchase {

enum State { Created, Locked, Inactive} // Enum

}

function getDefaultChoice() returns (uint){

return uint(defaultChoice);

}

}

变量

1.boolean布尔类型

就是true和false

操作有

!逻辑非

&&逻辑与

||逻辑或

==等

!=不等

2.Integer整形

uint和int型

有uint8和int8到uint256和int256

默认为uint256和int256

3.Address地址类型

比较重要,就是一个账户地址。20字节长,address有成员balance和send。

address x = 0x123;

address myAddress = this;

if (x.balance < 10 && myAddress.balance >= 10) x.send(10);

如果x是一个合约地址,代码会和send调用在一起运行(这是EVM的局限性)。如果代码用光gas也没执行完,那么会返回以太币,这时候,send调用会返回false。

send使用的不安全性:如果调用栈深度达到了1024(),交易会失败。或者接收方没了gas也会失败(?!)。所以转账时,要校验send函数的返回值,或者采用更好的方案:让接收方取钱。

call/delegatecall/callcode

调用call会返回一个布尔类型,表示函数调用完成(true)或者EVM抛出异常(false)。

delegatecall的作用差不多:但是区别在于,使用指定合约的代码,但是其他部分(比如存储、余额……)使用本合约。作用是类似于使用其他合约的代码作为库。

所有的合约都会继承address的成员,可以使用this.balance查看本合约地址。

4.固定大小的字符数组

bytes1, bytes2, bytes3, ..., bytes32.

byte默认是bytes1。

5.变长字符数组

bytes,就相当于特殊的byte[]

string,同上,唯一区别在于使用了UTF-8编码。

bytes有length和索引访问操作,bytes(str).length和bytes(str)[6]。

string没有各种操作,比如length和按索引访问string[0],非常难。

注:不能给函数传入二维变长数组,比如int[][] x,string[] str。

6.枚举

contract test {

enum ActionChoices { GoLeft, GoRight,GoStraight, SitStill }

ActionChoices choice;

ActionChoices constant defaultChoice = ActionChoices.GoStraight;

function setGoStraight() {

choice = ActionChoices.GoStraight;

}

// Since enum types are not part of theABI, the signature of "getChoice"

// will automatically be changed to"getChoice() returns (uint8)"

// for all matters external to Solidity.The integer type used is just

// large enough to hold all enum values,i.e. if you have more values,

// `uint16` will be used and so on.

function getChoice() returns (ActionChoices){

return choice;

}

7.函数类型变量

这个东西好像大多情况下用不到。最好先看下面的函数部分,再看这里。

内部函数变量只能在当前合约(包括内部库函数和继承函数)中使用,因为它们不能脱离当前合约的上下文执行。调用内部函数通过跳转到入口标签实现。

外部函数变量由一个地址和一个函数签名组成,并且它们可以由外部函数调用传递或者返回。

格式如下:

function () {internal|external}[constant] [payable] [returns ()]

如果有返回值,return type不能为空;如果没有返回值,那么就删掉[returns ()]

默认的function type是internal。

如果一个函数类型变量没有初始化或者删除了,调用它就会出现异常。

内部函数变量

闭上眼,用心去感受……

library ArrayUtils {

// internal functions can be used in internallibrary functions because

// they will be part of the same code context

function map(uint[] memory self, function(uint) returns (uint) f)

returns (uint[] memory r)

{

r = new uint[](self.length);

for (uint i = 0; i < self.length; i++){

r[i] = f(self[i]);

}

}

function reduce(

uint[] memory self,

function (uint) returns (uint) f

)

returns (uint r)

{

r = self[0];

for (uint i = 1; i < self.length; i++){

r = f(r, self[i]);

}

}

function range(uint length) returns (uint[]memory r) {

r = new uint[](length);

for (uint i = 0; i < r.length; i++){

r[i] = i;

}

}

}

contract Pyramid {

using ArrayUtils for *;

function pyramid(uint l) return (uint){

return ArrayUtils.range(l).map(square).reduce(sum);

}

function square(uint x) internal returns(uint) {

return x * x;

}

function sum(uint x, uint y) internal returns(uint) {

return x + y;

}

}

外部函数变量

contract Oracle {

struct Request {

bytes data;

function(bytes) external callback;

}

Request[] requests;

event NewRequest(uint);

function query(bytes data, function(bytes)external callback) {

requests.push(Request(data, callback));

NewRequest(requests.length - 1);

}

function reply(uint requestID, bytes response){

// Here goes the check that the replycomes from a trusted source

requests[requestID].callback(response);

}

}

contract OracleUser {

Oracle constant oracle = 0x1234567; // knowncontract

function buySomething() {

oracle.query("USD", oracleResponse);

}

function oracleResponse(bytes response){

if (msg.sender != oracle) throw;

// Use the data

}

}

8.引用类型。

对于一些大于256bit的的复杂的类型,比如数组和结构体等,会使用引用类型。引用类型有三种:memory(非永久)、storage(状态变量)还有calldata。

函数变量默认为memory类型;本地变量默认为storage类型;状态变量强制都是storage类型。calldata比较特殊,是不可修改的、非永久的区域,用于保存函数的参数。external函数的参数强制为calldata类型,跟memory类型差不多。

数据位置挺重要的,,它可以影响赋值语句的执行:storage和memory之间的赋值或者赋值给状态变量,都会产生一份独立的copy。赋值给本地的storage变量,则只赋一个引用,而且这个引用会永远指向一个状态变量,即使这个状态变量变化。而把一个memory的引用类型赋值给另一个memory引用类型也不会产生一个copy。

contract C {

uint[]x; //默认为storage

//memoryArray是memory

functionf(uint[] memoryArray) {

x = memoryArray; //memory到storage,x保存了一份copy

var y = x; // y是storage

y[7]; //没啥问题

y.length= 2; //通过改变y改变了x

delete x; //清空数组x,同时改变y

//下面这个不能用,不能把一个memory变量赋

// y = memoryArray;

//下面这个不能用,因为y没有一个pointer

// delete y;

g(x); //调用g函数,将x的引用传过去

h(x); //调用h函数,在memory中产生一个临时的copy

}

functiong(uint[] storage storageArray) internal {}

functionh(uint[] memoryArray) {}

}

对memory类型的变量长度,可以通过new关键字,来设定长度

storage类型 变量长度,不可以更改。

contract C {

functionf(uint len) { uint[] memory a = new uint[](7);

a[6] = 8;

}

}

Mappings映射

这是一个在solidity中比较重要的部分,可以被视为一个虚拟初始化的hash表,每一个可能的key默认为全0.

其中key的类型可以是除了mapping之外的任意类型,value可以是任意类型,包括mapping

contract MappingExample {

mapping(address=> uint) public balances;

functionupdate(uint newBalance) {

balances[msg.sender] = newBalance;

}

}

contract MappingUser {

functionf() returns (uint) {

return MappingExample().balances(this);

}

}

delete关键字hash

delete a相当于给a赋一个新的对象。

一些预置的变量和函数

block.blockhash(uint blockNumber) returns (bytes32):指定区块的hash,只有最近256个,其他全0

block.coinbase (address):当前的挖矿地址

block.difficulty (uint):当前区块难度

block.gaslimit (uint):当前区块的gaslimit

block.number (uint):当前区块数

block.timestamp (uint):当前区块时间戳

msg.data (bytes):完成calldata

msg.gas (uint):剩余gas

msg.sender (address):消息发送人

msg.sig (bytes4): calldata的前四个字节,即函数标识符

msg.value (uint):消息发送的以太币数,以wei为单位

now (uint):当前区块时间戳,跟上面的哪个一样。

tx.gasprice (uint):交易的gas单价

tx.origin (address):交易的发起人(全链上)

.balance (uint256):地址的余额

.send(uint256 amount) returns

(bool):发送给该地址制定以太币。j

this表示本合约的地址

selfdestruct(address recipient):销毁本合约,剩余资金转移到给定地址

预置函数

addmod(uint x, uint y, uint k) returns (uint):

mulmod(uint x, uint y, uint k) returns (uint):

keccak256(...) returns (bytes32):

sha3(...) returns (bytes32):

sha256(...) returns (bytes32):

ripemd160(...) returns (bytes20):RIPEMD-160

ecrecover(bytes32 hash, uint8 v, bytes32 r,

bytes32 s) returns (address):恢复地址的公钥

函数

内部函数调用

contract C {

functiong(uint a) returns (uint ret) { return f(); }

functionf() returns (uint ret) { return g(7) + f(); }

}

外部函数调用

contract InfoFeed {

functioninfo() payable returns (uint ret) { return 42; }

}

contract Consumer {

InfoFeedfeed;

functionsetFeed(address addr) { feed = InfoFeed(addr); }

functioncallFeed() { feed.info.value(10).gas(800)(); }

}

�]�%~��

你可能感兴趣的:(第四章 附部分solidity语法)