339-ethereum_solidity入门







solidity入门






数据类型分类
1.值类型(值传递)
2.引用类型(指针传递)
	1.memory(值类型)
	2.storage(引用类型)


先来说一下 值类型
1.boolean
2.integer
3.address
4.fixed byte array
5.rational and integer literals
6.enums
7.function types


然后来说一下 引用类型
1.string 
2.bytes
3.array
4.structs






我们来看一下简单的合约

pragma solidity ^0.4.24;

contract Inbox{
	string public message;
	
	function Inbox() payable{

	}

	function setMessage(string newMessage) public{
		message=newMessage;
	}

	function getMessage() public constant returns(string){
		return message;
	}
}






如果我们的合约已经部署到了以太坊上
但是我们不想要这个合约了
可以这样来做
function destroy(){
	selfdestroy(msg.sender);
}
调用之后,合约仍然存在于以太坊上,但是函数无法被调用
调用的话就会抛出异常
这样就相当于销毁了合约









状态变量
状态变量是在合约之内,函数之外的变量
有点像我们在其他语言中的成员变量

那么状态变量就是真的会将数据存储在以太坊的变量
比如刚刚的合约
contract Message{
	string public message;
}
这个message的值是真的会保存在以太坊的,也就是上链的






和状态变量相对的就是局部变量
比如
    function setMessage(string memory newMessage) public{
        string memory abc="abc";
        abc="ABC";
        message=newMessage;
    }
这里我们有一个局部变量abc
string memory abc="abc";
所以这里的abc是不会上链的







然后说一下 整型
1.int
2.uint
以8位为区间,支持int8,int16,int24至int256,uint同理
int默认为  int256
uint默认为 uint256

我们来写一点简单的例子
contract Test{
	function add(uint a, uint b) returns(uint){
		return a+b;
	}
}

我们再来写一个操作状态变量
contract Test{
    uint public c;
    
    function add(uint a, uint b) public {
        c=a+b;
    }
    
}

有一个小问题
pure

contract Test{
    
    function add(uint a, uint b) public pure returns(uint){
        return a+b;
    }
    
}







为什么要加pure呢
如果不加pure,会有这样的一个错误
我们来看一下
Warning: Function state mutability can be restricted 
to pure function add(uint a,uint b) 
翻译一下
函数状态的可变性可以限制为pure
也就是说,我们这里的add函数,并没有修改状态变量
那么就可以加上pure,这样的话,就是一个pure函数








我们再拿boolean举一个例子
    function isEqual(uint a) public pure returns(bool){
        return a==10;
    }
这个函数,就是做简单的判断
所以也是pure函数










然后说函数类型
1.public
2.private
3.external
4.internal
5.view/constant
6.pure
7.payable
8.returns

我们来说一下view/constant/pure的区别
view/constant是说没有修改状态变量
pure是说 根本没有使用到状态变量







然后说一下payable
payable的意思是,这个函数可以接收钱
我们举个例子
contract Test{
   	function invest() payable public{
		
	}
	
	function getBalance() public view returns(uint256){
		return address(this).balance;
	}
}

我们来看一下两个简单的函数
invest的话就可以接收钱
然后getBalance可以查看当前合约的余额

我们修改value为100wei
wei是以太坊的最小单位
然后invest
然后getBalance,我们发现余额变成了100







但是我们刚才的这个简单合约
是有问题的
问题就是,怎么把合约里的钱弄出来
我们这个合约是没有办法把钱弄出来的
这个我们以后再说







然后说一下构造函数
构造函数就是创建合约实例的时候,调用的函数
构造函数只调用一次
contract Test{
	constructor() public{
		
	}
	
}








匿名函数
function() payable{

}
就是两个单词,其他什么都没有
为什么要这么做
因为这样最便宜








然后说一下balance
contract Test{
	address account01 = 0x.....;
	
	function getBalance() public returns(uint256){
		return account01.balance;
	}
}

然后我们可以把这个合约修改成
谁调用,就看谁的余额







然后看一下transfer
我们来写一个例子
contract Test{
   	function getAccountBalance() public view returns(uint256){
   	    return msg.sender.balance;
   	}
   	function transfer(uint256 money) public{
		msg.sender.transfer(money);
	}
	function pay() public payable{
	}
	function getContractBalance() public view returns(uint256){
		return address(this).balance;
	}
}

这里例子中
我们通过getAccountBalance和getContractBalance
获取账户的余额和合约的余额
然后
pay方法就是账户付钱,到了合约里面
transfer方法就是合约付钱,到了账户里面










然后说一下 枚举
enum WeekDays{
	Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
}

WeekDays currentDay;
WeekDays defaultDay = WeekDays.Sunday;










string
不支持下标索引
不支持length,push
可以修改,需要通过bytes转换







结构体
struct Student{
	string name;
	uint age;
	uint score;
}







mapping
mapping(uint => string) id_names;
constructor() public{
	id_names[0x01]="Aaa";
	id_names[0x02]="Bbb";
	id_names[0x03]="Ccc";
}








msg.sender和msg.value
msg.sender就是当前交易的调用者

权限管理
举个例子
address public manager;
address public caller;

function Inbox() payable{
	manager=msg.sender;
}

function setMessage(string newMessage) public{
	caller = msg.sender;
	if (manager!=msg.sender){
		throw;
	}
	
	message=newMessage;
}

msg.value是记录当前msg.sender转了多少钱










区块和交易的属性
1.blockhash
2.block.coinbase	当前块矿工地址
3.block.difficulty	当前块难度
4.block.gaslimit	当前块gaslimit
5.block.number		块号
6.block.timestamp	时间戳
7.msg.data			完整的调用数据
8.gasleft()			当前剩余gas
9.msg.sender		当前调用发起人地址
10.msg.sig			调用数据的前4个字节
11.msg.value		消息所带的货币量,wei
12.now				等同于block.timestamp
13.tx.gasprice		交易的gas价格
14.tx.origin		交易的发送者










错误处理
throw是已经被废弃了
现在我们可以用
assert和require

举个例子
function setMessage(string newMessage) public{
	caller = msg.sender;
	require(manager==msg.sender);
	message = newMessage;
}

或者
assert(manager==msg.sender);










修饰器modifier
举个例子
modifier onlyManager{
	require(manager == msg.sender);
	_;
}

function setMessage(string newMessage) public onlyManager{
	caller=msg.sender;
	message=newMessage;
}










单位
货币单位
ether,wei,gwei
时间单位
seconds,minutes,hours,days,weeks,years








事件event
举个例子

contract ClientReceipt{
	event Deposit(
		address indexed _from,
		uint indexed _id,
		uint _value
	);
	
	function deposit(uint _id){
		Deposit(msg.sender, _id, msg.value);
	}
}

再举个例子
contract Test{
	event Deposit(
		address _from,
		uint _id,
		uint _value
	);
	
	mapping(address => uint) depositInfo;
	
	function deposit() public{
		depositInfo[msg.sender]=msg.value;
		emit Deposit(msg.sender,msg.value);
	}
}










访问函数
contract Test{
	string public name;
	function getName() public view returns(string){
		return name;
	}
	function setName(string _name) public{
		name = _name;
	} 
}

这种情况下,会自动生成一个
function name() public view returns(string){
	return name;
}

这是自动生成的变量同名函数
会方便很多










外部访问函数
contract TestA{
	string public name;
}

contract TestB{
	function getValue() public returns(string){
		TestA a = new TestA();
		return a.name();
	}
}












合约
contract TestA{
	string public name;
	function TestA(string _name) public{
		name = _name;
	}
}

contract TestB{
	TestA public a1;
	TestA public a2;
	TestA public a3;
	
	function getValue1() public returns(string){
		address addr = new TestA("hello");
		a1 = TestA(addr);
		return a1.name();
	}
	
	function getValue2() public returns(string){
		a2 = new TestA("hello");
		return a2.name();
	}
	
}











合约继承
contract Base1{
	function data() pure returns(uint){
		return 1;
	}
}

contract Base2{
	function data() pure returns(uint){
		return 2;
	}
}

contract son1 is Base1,Base2{

}

contract son2 is Base2,Base1{

}

这种情况下
是最远继承
也就是son1,return 2
son2,return 1










合约之间转账
contract TestA{
	string public message;
	
	function invest(string _input) payable public{
		message = _input;
	}
	
	function getBalance() public view returns(uint256){
		return address(this).balance;
	}
}

这时候,调用TestA的invest,就可以传入钱和值
然后

contract TestB{
	TestA public a1;
	
	constructor() public{
		a1 = new TestA();
	}
	
	function pay() public payable{
		a1.invest("I am TestB");
	}
}

这时候,调用TestB的pay










internal与external
举个例子
contract C1{
	uint public c = 10;
	function accessInternal() internal returns(uint){
		return c;
	}
	
	function accessExternal() external returns(uint){
		return c;
	}
	
	function call1() public returns(uint){
		//无法在内部调用accessExternal
		accessInternal();
	}
}

contract C2{
	function callExternal() public returns(uint){
		C1 c1 = new C1();
		c1.accessExternal();
		return c1.c();
	}
}










private		合约本身
internal	本身及子类
external 	合约外部
public		任意合约










元组 tuple
1.包含多个数据
2.类型可以不同uint,string
3.不可以修改
4.使用圆括号包裹









哈希函数keccak256
举例
bytes32 public hash = keccak256("hello",10,20,"abc");

bytes info = abi.encodePacked("hello",uint8(10),uint8(20),"abc");
bytes32 public hash = keccak256(info);










delete
举例
contract Test{
	string public str="abc";
	function deleteStr() public{
		delete str;
	}
}

1.可以用于任何变量(map除外),将其设置成默认值
2.如果对动态数组进行delete,删除所有元素
3.如果对静态数组进行delete,重置所有索引的值
4.如果对map使用delete,什么都不会发生
5.如果对map的一个键使用delete,删除与该键相关的值









合约销毁
pragma solidity >=0.4.22 <0.6.0;

contract Test{
	string public name;
	constructor(string memory _input) public payable{
		name=_input;
	}
	function getBalance() public view returns(uint256){
		return address(this).balance;
	}
	function kill() public{
		selfdestruct(msg.sender);
	}
}

最后执行selfdestruct的时候
会把合约里的钱转给msg.sender



















 

你可能感兴趣的:(solidity,ethereum)