Solidity变量类型分为两大类——值类型、引用类型
注意:值传递和引用传递。值类型的变量,赋值是简单的值传递,即两个变量占有独立的存储区域。引用类型赋值传递的是变量的引用,即两个变量指向同一存储区域
bool: 可能的取值为常量值true和false(默认false)。
bool a = true;
bool b = !a;
// a == b -> false
// a != b -> true
// a || b -> true
// a && b -> false
0/2^{m}-10/2m−1
有符号:
-2^{m-1}/2^{m-1}-1−2m−1/2m−1−1
比较:<=,<,==,!=,>=,>(结果为bool)
位操作符:&,|,^(按位异或),~(按位取反)
算术运算符:+, - ,一元 - ,一元 +,*,/,%(取余),**(幂),<<(左移),>>(右移)
到现在为止还没有被solidity完全支持,可以被声明,不能被赋值也不能用定点数赋值fixed/ufixed 各种大小的有符号和无符号定点小数,ufixedMxN and fixedMxN关键字M代表定点数占用的二进制位数,N代表定点数能表示多少位小数,M必须是8-256之间的,以8为步幅的整数,N必须是0-80之间的整数,ufixed 和fixed 默认为ufixed128x18和fixed128x18
地址:保存一个20字节值(40位16进制数)。地址类型也有成员,并作为所有合约的基础。
.balance (uint256)
.transfer(uint256 amount)
范例:
pragma solidity ^0.4.0;
contract AddressExample {
function AddressExample() payable{}
function giveEthersTo(address _toAccount,uint amount){
if (this.balance >=amount){
_toAccount.transfer(amount);
}
}
function getBalance() view returns(uint){
return this.balance;
}
}
.send(uint256 amount) returns (bool)
.call(...) returns (bool)
参数支持任何类型任意数量。每个参数会按规则被打包成32字节并一一拼接到一起。
call()函数支持ABI协议定义的函数选择器。如果第一个参数恰好4个字节,在这种情况下,第一个参数会被认为是指定的函数签名。所以如果你只是想发送消息体,需要避免第一个参数是4个字节。
pragma solidity ^0.4.0;
contract Person{
uint public age = 10;
uint public num ;
string public name;
bytes public data;
function increaseAge( uint _num,string _name) returns (uint){
num = _num;
name = _name;
data = msg.data;
return ++age;
}
function(){
data = msg.data;
age--;
}
}
contract CallTest{
bytes4 public methodId;
function callByFun(address addr)returns (bool){
methodId = bytes4(keccak256("increaseAge(uint256,string)"));
return addr.call(methodId, 1,"abc");
}
}
call函数返回一个bool值,以表明执行成功还是失败。正常结束返回true,异常终止返回false。
可以通过.gas()函数调整支付gas的数量
addr.call.gas(1000000)(1, "MyName");
可以通过.value()函数控制支付的以太币的数量
addr.call.value(1 ether)(1, "MyName");
这两个函数可以不分顺序同时使用
addr.call.gas(1000000).value(1 ether)(1, "MyName");
注意
address(this).balance
this.balance
bytes1, ... ,bytes32,允许值以步长1递增。byte默认表示bytes1。
.length产生字节数组的固定长度(只读)。
整数常量和有理数常量均支持科学计数法。基数可以是小数,指数必须是整数。 例如2e10,-2e10,2e-10,2.5e10
数字常量表达式一旦其中含有非常量表达式,它就会被转为一个非常量表达式
pragma solidity ^0.4.0;
contract IntegerLiteralConvert{
function literalTest(){
uint128 a = 1;
//uint128 b = 2.5 + a + 0.5;
//2.5+a不能转换成一个非常量表达式
}
}
字符串字面量是用双引号或单引号(“foo”或‘bar’)编写,长度可变。 它们不像C语言那样默认以0结尾; “foo”代表三个不是四个字节。 它们可以隐式转换为bytes1,…,bytes32。
pragma solidity ^0.4.0;
contract StringLiteralsTest{
bytes5 public name;
function setName(bytes5 _name){
name = _name;
}
}
十六进制常量,以关键字hex打头,后面紧跟用单或双引号包裹的字符串。如hex"001122ff"。 在内部会被表示为二进制流。通过下面的例子来理解下是什么意思:
pragma solidity ^0.4.0;
contract HexLiteral{
function test() returns (string){
var a = hex"7a6f757965";
//var b = hex"a";
//由于一个字节是8位,所以一个hex是由两个[0-9a-z]字符组成的。所以var b = hex“A”;不是成双的,转字符串是会报错的
return a;
}
}
//十六进制的常量与字符串可以进行同样的类似操作:
pragma solidity ^0.4.0;
contract HexLiteralBytes{
function test() returns (bytes4, bytes1, bytes1, bytes1, bytes1){
bytes4 a = hex"001122FF";
return (a, a[0], a[1], a[2], a[3]);
}
}
枚举类型是在Solidity中的一种用户自定义类型。
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;
// choice = ActionChoices(2);
}
function getChoice() public view returns (ActionChoices) {
return choice;
}
function getDefaultChoice() public pure returns (uint) {
return uint(defaultChoice);
}
}
function关键字声明的,合约中的可执行单元
function () {internal|external} [constant] [payable] [returns ()]
solidity的函数具有四种可见性:public、external、internal、private 默认public
内部函数(internal)
内部函数只能在所属合约,以及继承了所属合约的子合约中调用,调用方式是直接使用函数名
f()
外部函数(external)
外部函数可以在所属合约以外的地方调用,如果在所属合约内部调用也要使用外部函数的调用方式
this.f()
私有函数(private)
私有函数只能在所属合约中调用,调用方式是直接使用函数名
f()
公有函数(public)
公有函数可以在任何地方调用,在所属合约中调用,既支持内部调用方式,也支持外部调用方式。
f()
this.f()
public 或external 函数的特殊成员——函数选择器
pragma solidity ^0.4.16;
contract Selector {
function f() public view returns (bytes4) {
return this.f.selector;
}
}
范例
pragma solidity ^0.4.5;
contract FuntionTest{
function internalFunc() internal{}
function externalFunc() external{}
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`以`external`的方式调用一个外部函数
this.externalFunc();
}
}
contract FunctionTest1{
function externalCall(FuntionTest ft){
//调用另一个合约的外部函数
ft.externalFunc();
//不能调用另一个合约的内部函数
//Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//ft.internalFunc();
}
}
在internal和returns中间还可以加入一个配置属性,[pure|constant|view|payable]。
纯函数(pure)
既不从状态读取数据也不写入数据的函数可以被声明为纯函数 除了之前修改状态数据的情况外,我们认为一下情况属于从状态读取数据。
只读函数(constant/view)
不改变状态的函数可以被声明为只读函数一下几种情况被视为修改了状态:
constant是view的一个别名,会在0.5.0版本中遗弃,访问器(getter)方法默认被标记为view调用只读函数。
payable函数
是声明了该函数涉及支付操作,需要虚拟机提供事务支持,如果不声明的话,函数关于以太币交易的操作都会被拒回。
特殊的函数——回退函数
每一个合约可以有且仅可以有一个没有名字的函数。这个函数无参数,也无返回值。如果调用合约时,没有匹配上任何一个函数,就会调用默认的回退函数。
一个没有定义一个回退函数的合约。如果接收ether,会触发异常,并返还ether(solidity v0.4.0开始)。所以合约要接收ether,必须实现回退函数。下面来看个例子:
pragma solidity ^0.4.0;
contract Test {
uint x;
function() public payable {
x = 1;
}
function getX() view returns(uint){
return x;
}
function getBalance() view returns(uint){
return this.balance;
}
}
contract Caller {
function Caller()payable{}
function callTest(Test test) public {
test.call(0xabcdef01);
// test.transfer(2 ether);
}
function getBalance() view returns(uint){
return this.balance;
}
}
Solidity函数的输入参数的数量是可选的,也可以有任意数量的返回参数。
入参(Input Parameter)与变量的定义方式一致,稍微不同的是,不会用到的参数可以省略变量名称。一种可接受两个整型参数的函数如下:
pragma solidity ^0.4.0;
contract Simple {
function taker(uint _a, uint) {
// do something with _a.
}
}
出参(Output Paramets)在returns关键字后定义,语法类似变量的定义方式。返回结果的数量需要与定义的一致。如果给定了参数名,则函数可以不适用return关键字返回,如果没有给定参数名则需要函数体重使用return关键字按照顺序返回。
pragma solidity ^0.4.0;
contract Simple {
//return sum and product
function arithmetics(uint _a, uint _b) returns (uint o_sum, uint o_product) {
o_sum = _a + _b;
o_product = _a * _b;
}
}
pragma solidity ^0.4.0;
contract Simple {
//return sum and product
function arithmetics(uint _a, uint _b) pure returns (uint , uint ) {
return(_a + _b,_a * _b);
}
}
一个合约可以有多个名字相同、参数不同的函数,这些函数被称为重载函数。
要求:
输入参数类型不同或者输入参数个数不同(从本质上来说就是在调用的时候可以明确的区分开到底调用的是哪个函数,重载函数之前除了名字相同别无关联)