solidity基础-1
ReadMe
测试环境:系统win10x64,solidity版本:0.4.18
声明:该笔记参考Solidity入门系列,同时我会把学习时的错误理解也写出来,然后用删除线区别
-
整数
- 简介:
- solidity支持有符号整数和无符号整数
- 所占位数可以指定从
int8/uint8
到int256/uint256
,以8为步长,递增不同的长度;int/uint
默认都是256位。 - 整数支持数学运算符,位运算符和比较运算符
- 数学运算符:
+,-,一元+,一元-,*,/,%,**(求幂)
- 位运算符:
&,|,^,~
- 比较运算符:
<=,<,==,!=,>=,>
- 数学运算符:
- 除法截断:
- 字面量:是一种用于表达源代码中一个固定值的表示法
- 和其他语言一样,整数的除法运算总会被截断,例如:
1/4=0
,【但是使用字面量的方式则不会截断,例如:var e = 1/4
,当然可能也是var本身就具有智能推断的功能】此段待商榷
- 移位:
- 左移
<<
:相当于乘法,和C语言中的用法相同 - 右移
>>
:相当于除法,和C语言中的用法相同 - 所以:移位并不会改变符号位
- 注意:右移最小是0,例如:
1>>4=0
- 左移
- 异常:除以0或者对0取模,对一个值移负数位都会报异常
- 溢出:
- 上溢:如果一个整型变量的值达到其类型的上限,再给它加上一个正数,最终结果会是
(变量值 + 正数) - 类型上限
- 下溢:如果一个整型变量的值达到其类型的下限,再减去一个正数,会变成它的
上限值-该正数的值
- 上溢:如果一个整型变量的值达到其类型的上限,再给它加上一个正数,最终结果会是
- 简介:
- 地址
- 对比:以太坊提供的是账户模型,而比特币提供的是UTXO模型
- 地址(address):
- 一个地址代表一个账户,账户可以是普通的个人账户,也可以是包含代码的合约账户;因此在某些时候,地址代表的是一份合约代码
- 长度:固定20字节
- 支持的操作符:
<=,<,==,!=,=,>
- 成员:
-
balance
:查询地址的余额,可以用this.balance
来直接查询当前合约的余额,类型为uint
-
send
:使用send()
来向某个地址转账(货币单位是wei) -
call(),callcode(),delegatecall()
:支持传入任意类型的任意参数来直接与合约进行交互
-
- 参考资料:
-
以太币支付
- payable标识符:
- 函数上增加
payable
标识,即可接收ether
,并会把ether存在当前合约
- 函数上增加
- send()函数发送ether
- 地址对象中的
send()
可以向某地址直接进行支付- 如果是普通地址将会直接收到
- 但是合约要接收通过
send()
函数发送的ether,会有限制- 如果我们要在合约中通过
send()
函数接收,就必须定义fallback函数,否则会抛异常 -
fallback
函数必须增加payable
关键字,否则send()
执行结果将会始终为false
- 如果我们要在合约中通过
- 地址对象中的
- 支付中可能的失败
- send()失败
- 由于调试者可以强制指定调用堆栈的深度,当调用的栈深超过指定值时,一般为1024
- 接收地址处理支付过程中
out of gas
,即gas不够时
- 合约的fallback()
如果是合约地址,在执行send()时,默认关联执行fallback(),这是EVM的默认行为,不可阻止,所以这个函数引起的失败,交易会被撤销,send()为false
EVM:以太坊虚拟机,参考资料 - payable标识
如果一个函数要进行货币操作,必须带上payable
关键字,这样才能正常接收msg.value
- send()失败
- 参考资料:
- payable标识符:
-
定长字节数组
- 简介:
- 定义定长字节数组的方式是
bytesN
,N
的取值范围1~32
;byte
默认标识bytes1
- 定长字节数组的步长为
1
,整数类型的步长为8
- 定义定长字节数组的方式是
- 定义新变量
定义新变量时可以使用整数字面量,或者字符串字面量- bytes1 a = 255;
- byte a = "a";
- 用整数字面量定义时,注意取值范围,如:byte整数范围为
-128~255
- 运算符:
- 比较运算符有
<=,<,==,!=,>,=>
,返回的结果为bool
类型 - 位运算符:
&,|,^,~,<<,>>
移位操作符的右值必须为整数
,移位操作同样也要注意越界问题,越界会抛异常;如:byte a = 'a' << 1
,会报错,但是可以byte b = 'a';byte a = b << 1
这样通过中间变量来避免报错 - 不支持数学运算符
- 比较运算符有
- 使用序号访问定长字节数组:
可以使用序号来访问定长字节数组的某个字节;但是序号的取值不能超过定长字节数组的长度,和数组类似 - 长度:
定长字节数组提供了一个只读属性.length
来查看其长度,.length
的返回值类型是uint8
- 简介:
-
函数
关键字:
function
,类似于go语言中的func函数的参数:类似于C语言的函数参数,同样分实参和形参
-
命名参数:函数调用可以使用命名参数,将参数名和参数值这样的键值对以任意顺序放进
{}
即可,类似于go语言中的mapfunction f(uint k,uint v) returns(uint,uint) { return (k,v); } function g() returns(uint,uint) { return f({v:2,k:1}); }
-
函数的返回值:
-
返回值的定义与参数类似,跟在
returns
之后即可,如果在返回值中已经定义了变量,可以不调用return
,直接返回变量即可function f(uint a,uint b) returns(uint r) { r = a + b; }
return
关键字:和其他语言类似
-
函数的高级特性:
函数还支持跨合约函数调用的可见性控制,函数级别货币支付支持,函数级的访问控制等独有特性
-
函数的可见性与访问权限控制
- 简介:
介绍solidity作为一个分布式网络语言所特有的internal
和external
这两种不同的函数调用方式,以及solidity提供的对函数调用的可见性控制语法 - 调用方式:
-
internal:
internal
调用,实现时转为简单的EVM跳转,所以可以直接使用上下文环境中的数据,对于引用传递时将会变得非常高效
在当前的代码单元内,如对合约内函数,引入的库函数,以及父类合约中的函数直接使用即是以internal
方式的调用pragma solidity ^0.4.18; contract Test { function f() {} //以internal的方式调用 function call() { f(); } }
-
external:
external
调用,实现为合约的外部消息调用,所以在合约初始化时不能以external
的方式调用自身函数,因为合约还未初始化完成pragma solidty ^0.4.18; //contract afunction contract Afunction { //function f(uint k) external returns function f(uint k) returns(uint r) { r = k; } } contract bfunction { //以external的方式调用另一合约中的函数 //function callAfunction(afunction a) function callAfunction(Afunction a) { a.f(4); } }
和go语言一样,合约的首字母必须为大写才可以被外部合约调用;如果不大写的话,就必须为函数加上
external
,不然不能调用
external
调用时,实际是向目标合约发送一个消息调用。消息中的函数定义部分是一个24字节大小的消息体,20字节为地址,4字节为函数签名 this
我们可以在合约的调用函数前加this.
来强制以external
的方式调用,需要注意的是,这里的this
的用法与大多数语言都不一致。
当然,我们回到上面看一下external
的说明,在合约初始化时不能以external
的方式来调用自身函数,所以强制调用会报错,这也从反方面说明this.
的确是以external
方式调用调用方式说明:
上面所提到的internal
和external
指的是函数调用方式,请不要与后面的函数可见性声明:external
,public
,internal
,pravite
弄混,声明只是意味着这个函数需要使用相应的调用方式去调用。后续说明中会用以某某方式调用
,来强调是对调用方式的阐述以加以区分
-
- 函数的可见性
简介:solidity为函数提供了四种可见性:
external
,public
,internal
,pravite
-
external:
- 声明为
external
的函数可以从其他合约或通过Transaction
进行调用,所以声明为external
的函数是合约对外接口的一部分 - 不能以
internal
的方式进行调用 - 有时在接收大的数据数组时性能更好
声明为external
的函数只能以external
的方式进行调用;在同一个合约中调用声明为external
的函数,要用this.
强制调用,以internal的方式调用会报错
- 声明为
-
public:
函数默认声明为
public
pubic
的函数允许以internal
的方式调用,也允许以external
的方式调用-
public
的函数由于被外部合约访问,所以是合约对外接口的一部分pragma solidity ^0.4.18; contract FunctionTest { function publicFunc() {} function callFunc() { //以internal的方式调用 publicFunc(); //以external的方式调用 this.publicFunc(); } }
-
internal:
-
在当前的合约或继承的合约中,声明为
internal
的函数只允许以internal
的方式调用pragma solidity ^0.4.18; contract functionTest { //默认是public函数 function internalFunc() internal{} function callFunc() { //当前函数中的调用 internalFunc(); } } //solidity中用contract B is A //来表示,B是A的继承 contract functionTest1 is functionTest { function callinernalFunc() { //子合约中的调用 internalFunc(); } }
-
-
pravite:
- 只能在当前合约中被访问(不可以在继承合约中访问)
- 即使声明为
private
,仍能被所有人查看到里面的数据;访问权限只是阻止了其它合约访问函数或修改数据
- 简介: