solidity语法接近于Javascript,是一种面向对象的语言,是一种真正意义上运行在网络上的去中心合约。一些零散知识,记录下,如有不正确欢迎指出,努力学习中!部署用的是Remix在线编辑器。
版本申明
pragma solidity ^0.4.0;
说明
版本要高于0.4才可以编译
只要有了pure与view修饰符的函数,那么调用函数就不会消耗gas
view: 可以自由调用,因为它只是“查看”区块链的状态而不改变它,函数输出可以在调试时直接显示;
pure: 也可以自由调用,既不读取也不写入区块链
关键字:int,uint,intx,uintx(x为整形位数,如uint8范围为0~255)
关键字:bytesX(X为1~32),代表X字节,最好用0x来赋值
用.length获取长度,即X的值
只能整体修改,不能单独改某位
function change() public returns(bytes1){
by = 19;
by[0] = 1;//报错,不能单独改某一位
return by;
}
建立需要new
bytes public byy=new bytes(2);
function initbyy(){
//动态的可以用下标赋值
byy[0]=0x01;
byy[1]=0xfd;
}
function changelength(){
byy.length=5;//往后补0扩充位数
byy.push(0x99);//在最后加入,0x01fd00000099
}
不区分单双引号,只能利用bytes间接改与获取长度,注意处理中文与特殊字符(¥%&等),一个中文字符占3个字节,特殊字符还是占一个字节。
string Myname = "bobo";
function getmynamelength()view returns(uint){
return bytes(Myname).length;
}
function changemyname(){
bytes(Myname)[0]='L';
}
string Myname = "bobo";
function bytesx2bytes()view returns(string){
//函数体内部声明变量要加memory关键字申请内存
bytes memory name2=new bytes(bytes(Myname).length);
for(uint i=0;i<bytes(Myname).length;i++){
name2[i]=bytes(Myname)[i];
}
return string(name2);
}
长度固定,不能改长度,不能push元素,可以用length获取长度;
contract Fixarray{
uint[5] public arr=[1,2,3,4,5];
function init()public{
arr[0]=100;
arr[1]=200;
}
function getlength()returns(uint){
return arr.length;
}
}
定义时不指定长度,就可以随意添加更改数组,可以用push增加元素;
uint[] grade=[1,2,3];
function getContent() view returns(uint[]){
return grade;
}
function additem(){
grade.push(6);
}
function getlength()returns(uint){
return grade.length;
}
function changelength(){
grade.length=2;
}
定义固定长度时和其他一些语言行列是相反的,如下面例子uint[2][3],是有三行二列。但获取元素是正常的,和其他语言一样。
uint[2][3] map=[[1,2],[3,4],[5,6]];//这里2是列,3是行
function getContent2() view returns(uint[2][3]){
return map;
}
function getitem()view returns(uint){
return map[1][0];//output 3;map[2][0]=5
}
function getlength2() view returns(uint){
return map.length;//output 3
}
function getlength3() view returns(uint){
return map[0].length;//output 2
}
可变长度二维数组和可变数组定义类似。
Payable用于转账,balance获取账户金额
contract addr{
address public account = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
function changeitem()view returns(uint160){
return uint160(account);
}
//给此账户转账
function pay() payable{
}
//获取此账户金额
function getbalance() view returns(uint){
return this.balance;
}
}
//每个账户地址都有对应的transfer方法用于账户间转账
function trans()payable{
address acco=0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
acco.transfer(msg.value);
//acco.transfer(10 ether);
}
//返回给定区块号的哈希值,只支持最近256个区块,且不包含当前区块。在版本0.4.22种弃用并替换为blockhash(uint blockNumber)
block.blockhash(uint blockNumber)returns(bytes32)
//当前块矿工的地址
block.coinbase(address)
//当前块的难度
block.difficulty(uint)
//当前区块的块号
block.number(uint)
//当前块的Unix时间戳(从1970/1/1 00:00:00 UTC开始所经过的秒数)
block.timestamp(uint)
//完整的调用数据calldata
msg.data(bytes)
//当前还剩的gas,0.4.21版本弃用并替换为gasleft()
msg.gas(uint)
//当前调用发起人的地址
msg.sender(address)
//调用数据calldata的前四个字节
msg.sig(bytes4)
//这个消息所附带的以太币,单位为wei
msg.value(uint)
//当前块的时间戳(block.timestamp的别名)
now(uint)
//交易的gas价格
tx.gasprice(uint)
//交易的发送者(全调用链)
tx.origin(address)
使用合约转移指定以太币,首先得合约有钱,之后才能转;在value转移多于合约内指定的以太币,多余的以太币将保存在合约中。
低层send方法,和transfer方法一样,但send比较危险,一些异常交易不会报错。
pragma solidity ^0.4.0;
contract maptest{
mapping(address=>uint) idmapping; //0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 =>1
mapping(uint=>string) namemapping;//1=>name
uint sum=0;
//建立映射
function register(string name){
address account=msg.sender;
sum++;
idmapping[account]=sum;
namemapping[sum]=name;
}
function getID_by_address(address are)view returns(uint){
return idmapping[are];
}
function getname_by_ID(uint id)view returns(string){
return namemapping[id];
}
}
函数名相同,但传递参数不同(类型,数量),则称为函数重载。
当传入的参数不能区分是到底调用哪个重载的函数时编译报错,常常出现在虽然两个类型不同,但范围相同的关键字, 如uint160和address等。
有如下一些方式传递参数
pragma solidity ^0.4.0;
contract test{
uint public n;
string public na;
function setparam(uint num,string name){
n=num;
na=name;
}
function test1() {
setparam(10,"bobo");
}
function test2(){
setparam({num:10,name:"bobo2"});
}
function test3(){
setparam({name:"bobo2",num:10});
}
}
作用域遵行就近原则,函数内变量生命周期就是函数执行开始到结束。
使用external只能在外部调用,继承的合约也不能调用。可以使用this.来调用,这个属于外部调用。可以在一个新建合约创建那个含外部调用方法的合约,实现外部调用方法的调用。
pragma solidity ^0.4.0;
contract father{
function test() external view returns(string){
return "test";
}
//外部调用修饰符修饰的函数不能内部调用,下面注释的代码报错
// function dotest0()public view{
// test();
// }
//可以使用this.来调用
function dotest()public view{
this.test();
}
}
contract son is father{
//继承的合约也不能在内部调用有外部调用修饰符修饰的函数,下面代码报错
// function dotest0()public view{
// test();
// }
}
//新建合约可以调用
contract doexternal{
father f= new father();
function dotest0()public view{
f.test();
}
}
pragma solidity ^0.4.0;
contract zhichuandi{
uint public a=100;
uint public b=a;
function change(){
b=999;//a不变
}
//传递形参时这里传递的是副本,a本身不变
function change2(uint m)returns(uint){
m++;
return m;
}
function test(){
change2(a);
}
}
pragma solidity ^0.4.0;
contract gouzao{
address public ad;
uint public a;
//方式1
function gouzao(){
a=100;
}
//方式2
//构造函数可以有参数
function gouzao(uint aa){
a=aa;
}
//方式3
constructor(){
a=100;
ad=msg.sender;
}
}
pragma solidity ^0.4.0;
contract modifiertest{
address public owner;
uint public num=0;
constructor(){
owner=msg.sender;
}
//定义modifer
modifier onlyowner{
require(msg.sender==owner);//判断当前地址是否是合约拥有者
_; //动态添加
}
//附加上modifer,先执行modifer的第一条语句
//即判断当前地址是否是合约拥有者,通过则执行下列语句,否则报错
function change(uint _num) onlyowner{
num=_num;
}
}
下面分析告诉你答案,意会吧。
contract mulmodifier{
uint public a=0;
modifier mod1{
a=1;
_;
a=2;
}
modifier mod2{
a=3;
_;
a=4;
}
//下划线是一个整体
//a=1 -> a=3 -> a=100 -> a=4 -> a=2;
function test() mod1 mod2{
a=100;
}
}
pragma solidity ^0.4.0;
contract grandfather{
uint public company=10000;
}
contract father is grandfather{
uint public money =1000;
function house() public returns(string){
return "house";
}
}
contract son is father{
function getmoney()returns(uint){
return money;
}
function test()returns(string){
return house();
}
}
- 只能继承没有修饰的,public,internal的相关属性,private属性不可继承
- public,internal,external修饰的函数可以被继承,external要用this.来调用,private修饰的函数不可继承
- public:内部外部都可调用 Internal:只能内部调用 External:只能外部调用
- pure:不会读取全局变量,也不会修改全局变量,一个固定输入就会有一个固定输出
- Constant:在修饰函数时,与view相同,在全局变量中,只用于bytes1-bytes32,uint,int,string,数据不可修改
- View:只读取全局变量的值,不修改,不消耗gas
- Payable:转账必须加的关键字
在定义全局变量时,相当于定义了一个与变量名一致的getter函数,用于获取此变量的值,需要外部调用,即this.变量名()
当子合约与父合约的属性相同时,会发成重载,覆盖掉父合约的属性。
函数也一致,会覆盖重名的父合约的函数。
如果子合约有与父亲和母亲一样的属性,同样会覆盖掉。
contract father{
uint public money=1000;
}
contract mother{
uint public money=1200;
}
//继承顺序影响着相同属性的继承,下面例子输出1200
contract son is father,mother{
function getmoney()returns(uint){
return money;
}
}
contract destruce{
address public owner;
constructor(){
owner=msg.sender;
}
function kill{
if(msg.sender==owner){
selfdestruct(owner)
}
}
}
contract memorytest{
struct student{
uint id;
string name;
}
function test(student s)internal{
student memory ss=s;
}
function init()returns(uint,string){
//student memory s = student(100,'bobo');
student memory s = student({id:100,name:'bobo'});
return (s.id,s.name);
}
}