Solidity中的契约类似于面向对象的语言中的类。每个合约都可以包含状态变量,函数, 函数修饰符,事件,结构类型和枚举类型的声明。此外,合同可以继承其他合同,在Solidity中每一个类都被称为合同。
以下类型也被称为值类型,因为这些类型的变量将始终按值传递,即它们在用作函数参数或赋值时总是被复制。
bool
:可能的值是常量true
和false
。
!
(逻辑否定)&&
(逻辑连词“and 和”)||
(逻辑和,“或”)==
(平等)!=
(不等式)||
和
&&
都有编程语言的共同短路规则
运算符
<=
,<
,==
,!=
,>=
,>
(计算结果为bool
)&
,|
,^
(按位异或), ~
(按位取反)+
,-
,一元-
,一元+
,*
,/
,%
(余数), **
(幂), <<
(左移位),(>>
右移位)
int
/
uint
:各种大小的有符号和无符号整数。关键字
uint8
以
uint256
在步骤
8
(无符号的8到256位)和
int8
到
int256
。
uint
并
int
分别为
uint256
和别名
int256
。
除以零和模数除以零将引发运行时异常。
移位操作的结果是左操作数的类型。这个表达式相当于,相当于。这意味着转移负数的符号延伸。按负数移动会引发运行时异常。x << y
x * 2**y
x >> y
x / 2**y
address
:保存20个字节的值(以太坊地址的大小)。地址类型也有成员,并作为所有合同的基础。
balance
和 transfer
address x = 0x123;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
如果
x
是合同地址,则其代码将与该
transfer
呼叫一起执行(这是EVM的一项功能,无法阻止)。如果执行耗尽或以任何方式失败,以太转移将被恢复,并且当前合同将停止,除了例外
send
transfer
。如果执行失败,则当前合同不会停止,但
send
将返回
false
。
使用中存在一些不安全的send
:如果调用堆栈深度为1024(调用程序始终强制调用堆栈深度),则调用失败,如果收件人耗尽Gas,调用堆栈深度也将失败。所以为了安全的传输,总是检查返回值send
,使用transfer
甚至更好:使用接收者提取钱的模式。
call
,callcode
和delegatecall
call
返回一个布尔值,指示调用的函数是否终止(
true
)或导致EVM异常(
false
)。不可能访问返回的实际数据(为此,我们需要事先知道编码和大小)。
可以用.gas()
改性剂调整供给的气体:
namReg.call.gas(1000000)("register", "MyName");同样,所提供的以太值也可以被控制:
nameReg.call.value(1 ether)("register", "MyName");最后,这些修饰符可以合并。 他们的顺序无关紧要:
nameReg.call.gas(1000000).value(1 ether)("register", "MyName");
bytes1
,
bytes2
,
bytes3
,...,
bytes32
。
byte
是别名
bytes1
。
成员:
.length
产生字节数组的固定长度(只读)。bytes
:
string
:
作为一个经验法则,使用bytes
任意长度的原始字节数据和string
任意长度的字符串(UTF-8)数据。如果你可以限制长度到一定数量的字节,总是使用其中之一bytes1
,bytes32
因为它们便宜得多。
0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF
是
address
类型的。长度在39到41位之间的十六进制文字不通过校验和测试会产生警告,并被视为常规的有理数字文字。
69
意味着六十九。069是无效的。
十进制小数文字是由.
一边至少有一个数字组成的。例子包括1.
,.1
和1.3
。
科学记法也是支持的,基数可以有分数,而指数不能。实例包括2e10
,-2e10
,2e-10
,2.5e1
。
数字文字表达式保持任意精度,直到它们被转换为非文字类型(即通过与非文字表达式一起使用它们)。这意味着计算不会溢出,并且分区不会在数字文字表达式中截断。
例如,结果是常量(类型),尽管中间结果甚至不适合机器字的大小。此外,整数的结果(虽然之间使用非整数)。(2**800 + 1) - 2**800
1
uint8
.5 * 8
4
只要操作数是整数,任何可以应用于整数的运算符也可以应用于数字文字表达式。如果两者中的任何一个都是小数,则位操作是不允许的,如果指数是小数(因为这可能导致一个非有理数),指数是不允许的。
对于每个有理数,Solidity都有一个数字字面类型。整数文字和有理数字文字属于数字文字类型。而且,所有数字文字表达式(即仅包含数字文字和运算符的表达式)属于数字文字类型。所以数字文字表达式和二者属于相同的数字文字类型的有理数三。1 + 2
2 + 1
字符串文字用双引号或单引号("foo"
或'bar'
)编写。它们并不意味着像C中一样跟随零; "foo"
代表三个字节而不是四个。与整数文字,它们的类型可以不同,但它们是隐式转换为bytes1
,... bytes32
,它们是否适合,要bytes
和string
。
字符串字面支持转义字符,如\n
,\xNN
和\uNNNN
。\xNN
取一个十六进制值并插入相应的字节,同时\uNNNN
取一个Unicode码点并插入一个UTF-8序列。
十六进制文字以关键字为前缀,hex
并用双引号或单引号(hex"001122FF"
)括起来。他们的内容必须是一个十六进制字符串,它们的值将是这些值的二进制表示。
十六进制文字行为像字符串文字,并具有相同的可转换性限制。
枚举是在Solidity中创建用户定义类型的一种方法。它们可以显式转换为所有整数类型,但是不允许隐式转换。显式转换检查运行时的值范围,失败会导致异常。枚举需要至少一个成员。
contract test { enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } ActionChoices choice; ActionChoices constant defaultChoice = ActionChoices.GoStraight; function setGoStraight() public { choice = ActionChoices.GoStraight; } // Since enum types are not part of the ABI, 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() public view returns (ActionChoices) { return choice; } function getDefaultChoice() public pure returns (uint) { return uint(defaultChoice); } }
函数类型是函数的类型。函数类型的变量可以由函数赋值,而函数类型的函数参数可以用来将函数传递给函数调用并返回函数。函数类型有两种类型 - 内部函数和外部函数:
内部函数只能在当前合约(更具体地说,在当前代码单元内部,也包括内部函数库和继承函数)内部调用,因为它们不能在当前合同的上下文之外执行。调用内部函数是通过跳转到它的入口标签来实现的,就像在内部调用当前合同的函数一样。
外部函数由一个地址和一个函数签名组成,它们可以通过外部函数调用传递并返回。
函数类型如下所示:
function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)]
与参数类型不同,返回类型不能为空 - 如果函数类型不返回任何内容,则 必须忽略整个部分。returns ( types>)
contract Selector { function f() public view returns (bytes4) { return this.f.selector; }