强烈不建议使用!!
为了方便,并不总是需要明确指定一个变量的类型,编译器会通过第一个向这个对象赋予的值的类型来进行推断
uint24 x = 0x123;
var y = x;
由var引发的血案…
需要特别注意:由于类型推断是根据第一个变量进行的赋值。所以下面的代码将是一个无限循环,因为一个uint8的i的将小于2000。
for (var i = 0; i < 2000; i++)
{
//uint8 -> 255
//无限循环
}
pragma solidity ^0.4.25;
contract Test{
function Hi() view returns (uint, uint){
uint count = 0;
var i = 0;
for (; i < 257; i++) {
count++;
if(count >= 260){
break;
}
}
return (count, i);
}
}
/*
结果:
0: uint256: 260
1: uint256: 3
分析:当 循环到 i =255 时,count = 256,再往后 i 又从0开始了!
i , count
255 , 256
0 , 257
1 , 258
2 , 259
3 , 260
*/
函数 | 含义 |
---|---|
block.blockhash(uint blockNumber) | 哈希值(byte32) |
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)调用数据的前四个字节(函数标识符) |
msg.value | (uint)这个消息所附带的货币量,单位为wei |
now (uint)当前块的时间戳 | 等同于block.timestamp |
tx.gasprice | (uint) 交易的gas价格 |
tx.origin | (address)交易的发送者(完整的调用链) |
pragma solidity ^0.4.25;
contract Test {
bytes32 public blockhash;
address public coinbase;
uint public difficulty;
uint public gaslimit;
uint public blockNum;
uint public timestamp;
bytes public calldata;
uint public gas;
address public sender;
bytes4 public sig;
uint public msgValue;
uint public now;
uint public gasPrice;
address public txOrigin;
function letgo (){
//给定区块号的哈希值,只支持最近256个区块,且不包含当前区块
blockhash = block.blockhash(block.number - 1);
coinbase = block.coinbase ;//当前块矿工的地址。
difficulty = block.difficulty;//当前块的难度。
gaslimit = block.gaslimit;// (uint)当前块的gaslimit。
blockNum = block.number;// (uint)当前区块的块号。
timestamp = block.timestamp;// (uint)当前块的时间戳。
calldata = msg.data;// (bytes)完整的调用数据(calldata)。
gas = msg.gas;// (uint)当前还剩的gas。
sender = msg.sender; // (address)当前调用发起人的地址。
sig = msg.sig;// (bytes4)调用数据的前四个字节(函数标识符)。
msgValue = msg.value;// (uint)这个消息所附带的货币量,单位为wei。
now = now;// (uint)当前块的时间戳,等同于block.timestamp
gasPrice = tx.gasprice;// (uint) 交易的gas价格。
txOrigin = tx.origin;// (address)交易的发送者(完整的调用链)
}
}
wei
,finney
,szabo
或ether
来在不同面额中转换。wei
。如1 ether
== 1000 finney
的结果是true
。pragma solidity ^0.4.25;
contract EthUnit{
uint a = 1 ether;
uint b = 10 ** 18 wei;
uint c = 1000 finney;
uint d = 1000000 szabo;
function f1() constant public returns (bool){
return a == b;
}
function f2() constant public returns (bool){
return a == c;
}
function f3() constant public returns (bool){
return a == d;
}
function f4() constant public returns (bool){
return 1 ether == 100 wei;
}
}
pragma solidity ^0.4.25;
contract TimeUnit{
function f1() pure public returns (bool) {
return 1 == 1 seconds;
}
function f2() pure public returns (bool) {
return 1 minutes == 60 seconds;
}
function f3() pure public returns (bool) {
return 1 hours == 60 minutes;
}
function f4() pure public returns (bool) {
return 1 days == 24 hours;
}
function f5() pure public returns (bool) {
return 1 weeks == 7 days;
}
function f6() pure public returns (bool) {
return 1 years == 365 days;
}
}
pragma solidity ^0.4.0;
contract ClientReceipt {
//定义,注意,需要加分号,相当于一句语句,与struct和enum不同。
event Deposit(
address indexed _from,
uint indexed _id,
uint _value
);
function deposit(uint _id) {
//使用
Deposit(msg.sender, _id, msg.value);
}
}
public的状态变量
创建访问函数。下面的合约例子中,编译器会生成一个名叫data的无参,返回值是uint的类型的值data。状态变量的初始化可以在定义时完成。pragma solidity ^0.4.25;
contract C{
uint public data = 10;
}
contract D{
C c = new C();
function getDataUsingAccessor() returns (uint){
return c.data();
}
}
pragma solidity ^0.4.25;
contract viewTest{
uint public c = 10;
function accessInternal() internal view returns (uint){
return c;
}
//合约内部也能够调用用external修饰的函数, 但是要使用外部调用方式this
function accessExternal() view external returns (uint){
return this.c();
}
}
传统方法:采用 throw 和 if … throw 模式==(已过时)==,例如合约中有一些功能,只能被授权为拥有者的地址才能调用
if(msg.sender != owner) {
throw;
}
等价于如下任意一种形式:
if(msg.sender != owner) {
revert();
}
assert(msg.sender == owner);
require(msg.sender == owner);
示例:
pragma solidity ^0.4.21;
contract HasAnOwner {
address public owner;
uint public a ;
constructor() public {
owner = msg.sender;
}
function useSuperPowers() public {
require(msg.sender == owner);
a = 11111;
/*
if (msg.sender != owner){
throw;
}
*/
a = 10;
// do something only the owner should be allowed to do
}
}
修改器(Modifiers)可以用来轻易的改变一个函数的行为。比如用于在函数执行前检查某种前置条件。修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)。下面我们来看一段示例代码:
pragma solidity ^0.4.21;
contract HasAnOwner {
address public owner;
uint public a ;
constructor() public {
owner = msg.sender;
}
modifier ownerOnly(address addr) {
require(addr == owner);
//代码修饰器所修饰函数的代码
_;
}
function useSuperPowers() ownerOnly(msg.sender) public {
//require(addr == owner);
a = 10;
// do something only the owner should be allowed to do
}
}
元组是一个数据集合,类似于字典但是无法修改数据,使用圆括号包括多种数据类型。
pragma solidity ^0.4.25;
contract Test {
struct Student {
string name;
uint age;
uint score;
string sex;
}
//两种赋值方式
Student public stu1 = Student("lily", 18, 90, "girl");
Student public stu2 = Student({name:"Jim", age:20, score:80, sex:"boy"});
Student[] public Students;
function assign() public {
Students.push(stu1);
Students.push(stu2);
stu1.name = "Lily";
}
//1. 返回一个Student结构
function getLily() public view returns(string, uint, uint, string) {
Student memory lily = Students[0];
return (lily.name, lily.age, lily.score, lily.sex);
}
}
ripemd160
keccak256
addmod
ecrecover
父合约
代码复制到 子合约
pragma solidity ^0.4.25;
//父合约
contract Father{
string public fatherName = "James";
}
//子合约
contract Son is Father{
string public sonName = "Jun";
function testFather() public{
fatherName = "James01";
sonName = "Jun01";
}
}
pragma solidity ^0.4.25;
//父合约
contract Father{
string public fatherName = "James";
function printName() public view returns(string){
return fatherName;
}
}
//子合约
contract Son is Father{
string public sonName = "Jun";
function testFather() public{
this.sonName = "Jun01";
super.fatherName = "James01";
super.printName();
}
}
pragma solidity ^0.4.25;
contract Father{
string public fatherName = "James";
function outName() public view returns(string){
return fatherName;
}
}
contract Son is Father{
string public fatherName = "James2";
string public sonName = "Jun";
function outName() public view returns(string){
return super.outName();
}
}
contract Father{
uint public stateVar;//成员变量
//public 方法
function aPublicFun() public pure returns(string){
return "publicFunc invoked";
}
function aInternalFun() internal pure returns(string){
return "internalFunc invoked";
}
function aExternalFun() external pure returns(string){
return "externalFunc invoked";
}
function aPrivateFun() private pure returns(string){
return "privateFunc invoked";
}
}
// 子合约 继承 父合约
contract Son is Father{
function testFather() public{
//不能访问`private`
//aPrivateFun();
//访问父类的`public`方法
aPublicFun();
//访问父类的状态变量
stateVar = 10;
//访问父类的`internal`方法
aInternalFun();
//访问父类的'external'方法,需要通过this关键字
this.aExternalFun();
}
// 调用某合约访问权限是external的方法
function testExternal(Father fObj)public view returns(string){
return fObj.aExternalFun();
}
}
问题:如果父合约 与 子合约 中 有 相同名字 的 成员变量 或 方法的话,会怎么样?
答:不管同名与否,父合约所有成员都会被 “继承” 到 子合约中。只是子合约调用时有些区别。
pragma solidity ^0.4.25;
contract Father{
string public fatherName = "James";
}
contract Son is Father{
string public fatherName = "James2";
function outName() public view returns(string){
return fatherName; // James2
}
}
pragma solidity ^0.4.0;
contract Base1{
function data() public view returns(uint){
return 1;
}
}
contract Base2{
function data() public view returns(uint){
return 2;
}
}
contract MostDerived1 is Base1, Base2{ // extends Base2 (most derived)
function call() public view returns(uint){
return data(); // Base2.data()
}
}
contract MostDerived2 is Base2, Base1{ // extends Base1 (most derived)
function call() public view returns(uint){
return data(); // Base1.data()
}
}
pragma solidity ^0.4.0;
contract owned {
function owned() { owner = msg.sender; }
address owner;
}
contract mortal is owned {
event mortalCalled(string);
function kill() {
mortalCalled("mortalCalled");
if (msg.sender == owner) selfdestruct(owner);
}
}
contract SpecifyBase is mortal {
event SpecifyBase(string);
function kill() {
SpecifyBase("do own cleanup");
mortal.kill();
}
}
外部调用,后面项目会用到
pragma solidity ^0.4.24;
contract C1 {
uint public num = 10;
function setValue(uint a) public {
num = a;
}
}
//手动赋值
contract C2 {
C1 c1;
function call (address addr) public {
c1 = C1(addr);
c1.setValue(100);
//addr.setValue(1000); 不允许
}
}
//合约自动调用
contract C3 {
C1 c1;
function C3() {
address c1Addr = new C1();
c1 = C1(c1Addr);
//或者 直接使用C1来承接亦可
//c1 = new C1();
}
function getValue() public constant returns(uint) {
return c1.num();
}
//注意constant 的坑!!!!,
//函数加上constant之后,运行修改状态变量,但是修改不会生效,好坑!!!
function setValue(uint num) public {
c1.setValue(num);
}
}
官方示例
pragma solidity ^0.4.0;
contract InfoFeed {
function info() public payable returns (uint ret) {
return 42;
}
}
contract Consumer {
InfoFeed feed;
function setFeed(address addr) public {
feed = InfoFeed(addr);
}
function callFeed() public {
feed.info.value(10).gas(800)();
}
}