Solidity 基础知识 | 以太坊智能合约编程语言

2,513 阅读8分钟

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

在这里插入图片描述

Solidity是一种智能合约高级语言,运行在Ethereum虚拟机(EVM)之上。Solidity是以太坊的首选语言,它内置了Serpent的所有特性,它的语法接近于Javascript,是一种面向对象的语言,这降低了学习门槛,易于被掌握和使用,因为JavaScript是Web开发者的常用语言。因此,Solidity充分利用了现有数以百万程序员已掌握JavaScript这一现状。

以太坊智能合约编程语言,语法简单,但是有不成熟不完善,有bug,没有多线程

注意事项

编译器选择

使用的是Remix IDE编译器 下载地址 ---> Remix IDE下载地址 这个编译器对中文很不友好!吐槽一下!

一些说明

  1. 一个 contract 里面就是一个合约,没有main函数,只要合约部署就可以运行
  2. 一定要有头部版本号申明:pragma solidity 0.4.24;
  3. 每一行结尾得有分号(;)结束

注释:中文必须在外面写好然后拷贝,不能直接在里面写中文注释!对中文很不友好! 在这里插入图片描述


1. 变量

1.1 状态变量

定义在合约之内,但是在函数之外的变量,叫做状态变量,这些变量会上传到区块链保存的,默认是私有的,可以使用public和private修饰

pragma solidity 0.4.24; 

contract HelloWorld{
    string public name;   // 这个就是状态变量,使用public修饰
    function hello(string memory text) public pure returns(string memory) {
        return text;
    }
}

1.2 局部变量

合约之内,在函数之内,局部变量不能使用public

pragma solidity 0.4.24;

contract Hello{

    function hello(string memory text) public pure returns(string memory) {
        string name = "FanOne";   // 这个就是局部变量
        return text;
    }
}

状态变量默认是私有的,可以使用public修饰

2. 数据类型

2.1 值类型

2.1.1 布尔类型(Booleans):

truefalse,默认是false

逻辑非
&& 逻辑与 || 逻辑或 == 等于 != 不等于

pragma solidity 0.4.24;

contract DataType {

    // bool public ok = true;
    bool public ok;  // def is false

    function test() returns(string){
        if (ok) {
            return "this is true";
        }else {
            return "this is false";
        }
    }
}

2.1.2 整型(Integers):

int/uint: 表示有符号和无符号不同位数整数

以8位为区间,有int8,int16,int24,...,int256,int默认是int256,uint同理

int8 num;
int256 total = 120;

举例:两个数相加的结果

pragma solidity 0.4.24;
contract Add {
  int8 i1 = 10;
  int16 i2 = 11;
  function add() returns (int8){
      return i1 + int8(i2); // 类型强转
  }
}

2.1.3 定长浮点型(Fixed Point Numbers):

fixed/ufixed: 表示有符号和无符号的固定位浮点数

还不完全支持,它可以用来声明变量,但不可以用来赋值

2.1.4 定长字节数组(Fixed-size byte arrays)

关键字有:bytes1, bytes2, bytes3, ..., bytes32。 byte 代表 bytes1。bytes1存储1个字节,即8位,bytes2存储2个字节,步长为1字节递增 .length:表示这个字节数组的长度(只读),返回的是定长字节数组类型的长度,而不是值的长度 长度不能修改 可以通过下标获取 元素值不可修改,只读

pragma solidity 0.4.24;

contract TestBytes {
    bytes1 public b0;  // 字节:0x00
    bytes1 public b1 = "f";  // 0x66
    bytes2 public b2 = "fa";  // 0x6661
    bytes6 public b6 = "fanone";  
    bytes32 public b32 = "FanOne";
    function getLen() returns(int256){
        return b32.length;
    }
    function getByIndex() returns(bytes1){
        return b1[0];
    }
}

在这里插入图片描述

2.1.5 有理数和整型常量(Rational and Integer Literals)

表达式中直接出现的数字常量:

整数,小数,科学计数都支持(9e30:6*200^10)

2.1.6 枚举(Enums)

自定义类型 至少要有一个元素,默认位uint8,不要忘了花括号

enum Gender {
 	Male, 
 	FeMale 
 }

// Gender为自定义类型,设置默认值

Gender default = Gender.Male 

2.1.7 函数类型(Function Types)

  • 状态变量:默认是private
  • 函数:默认是public

修饰符

public:公有,拥有以太坊的账户都可以调用,可以修饰状态变量 private:私有,只有合约内部可以调用,可以修饰状态变量 view / constant:函数会读取但是不会修改任何合约的状态变量 pure:函数不适用任何合约的状态变量 payable:调用函数需要付钱,钱付给了智能合约的账户 returns:返回值函数声明中使用 external:仅合约外部可以调用,合约内部需要使用this调用 internal:仅合约内部和继承的合约可以调用

修饰符在returns声明的前面,可以有多个修饰符

viewconstantpure的区别:都是针对状态变量的 函数中访问了状态变量,但是没有修改,使用view或者constant 如果没有使用状态变量,则使用pure修饰 如果即访问了状态变量,又修改了,则不要修饰即可。 注意坑:constant修饰的函数中,修改了状态变量,编译器不会报错,但是运行是修改不成功的。

payable

想要转钱,修饰符必须是payable

payable的修饰符,转的钱到合约中了

function setMoney(string str) public payable returns(string) {
    return str;
}

部署的时候,交易金额给个值,会发现金额减少了,钱到了合约,注意交易金额的单位,用ether,不然看不到大的变化 获取合约中的钱

function getMoney() public view returns(uint256){
     return this.balance;
}

this代表当前合约本身,balance获取当前合约的余额

函数定义

function 函数名称(可选参数) 修饰符 返回值{ 函数体 }

例:

function Add(a int8) public view returns(int8){
    return a
}

函数返回值

  • 使用returns指定返回的类型

  • 返回值声明一定要放在最后

  • 多个返回值使用元组:使用括号括起来()

构造函数

进入合约就执行,一般设置一些初始化后不变的数据

constractor() public {
    owner = msg.sender;
}

public:共有,可以修饰函数,可以修饰状态变量 provate:私有,可以修饰函数,可以修饰状态变量 view/constant:用了状态变量,但是没有修改状态变量,只能修饰函数 pure:没有使用状态变量,只能修饰函数 payable:只能修饰函数,转账的话必须使用payable,钱从账户过来,钱到合约 returns:在函数最后,返回值

状态变量在函数中修改了,就不要使用(view\constant\pure)修饰符

2.1.8 地址类型(Address)

基础知识

地址是所有合约的基础,所有合约都继承地址对象 通过合约的地址串,调用合约内的函数,本质是uint160,可以进行加减,需要强转

balance:获取余额 transfer:转账,推荐使用,谁调用就是给谁转 send:转账,不安全,不推荐使用,合约余额不够需要自己手动处理,不会报错 call:合约内部调用合约,调用底层代码,别用 callcode:调用底层代码,别用 delegatecall:调用底层代码,别用 this指合约本身

address(this),直接使用this会有warning

账户-->账户:不支持 账户--合约:paybable 合约--账户:transfer,谁调用就是给谁转 合约--合约 看高级用法 换算:1ether = 10**18wei (10^18),单位默认是wei

转账

pragma solidity 0.4.24;

contract TransferDemo {
    uint256 public a;
    function constractGetMoney() public payable{
        
    }
    function getConstractBalance() public {
        a = address(this).balance;
    }
    address to_addr = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;
    function trans() public {
        to_addr.transfer(5 * 10 ** 18 );  //define is wei
        //need to transfer eth
    }
}

这里有很多地址可选择 在这里插入图片描述

在这里插入图片描述

钱到哪去:向谁转钱,就用谁调用transfer 钱从哪来:合约的钱(payable),合约的钱不够transfer的时候会报错

在这里插入图片描述

2.2 引用类型

2.2.1 字符串

  1. 不支持索引
  2. 不支持length和push方法
  3. 可以修改,需要通过bytes转换
string me = "fanone";

转bytes,然后就可以使用bytes的特性了

bytes(me).length;

bytes转string

string(bytes)

不定长字节数组:bytes:

  • 支持length,push(在最后追加)方法
  • 可以修改
  • 支持索引,如果未分配空间(new分配空间),使用下标会报角标越界,其他的会自动分配空间
  • 以十六进制格式赋值
bytes me = "fanone"
name.push("666")

2.2.2 数组

  • 内置数组:string、bytes、bytes1...bytes32

  • 自定义定长数组:长度不可变,支持length,不支持push

uint256[5] public nums = [1,2,3,4,5];
  • 自定义不定长数组:长度可变,内容可修改,支持length,push方法
uint256[] public nums = [1,2,3,4,5];
nums.push(6)
delete nums;
  • 函数中使用new分配空间
uint8[] memory aa = new uint8[](10);// 10个长度的空间

2.2.3 结构体:

函数不支持返回结构体对象,可以把值放到元组中返回(按个放到()中,返回元组)

struct 结构体名称{
    类型 字段名;
}
 struct Person {
    string name;
    uint age;
}

// 指定字段名,必须用()括起来,里面是花括号
Person public p1 = Person({name:"hallen",age:18});
// 按顺序初始化值,注意是括号()不是花括号{}
Person public p2 = Person("hallen",18);
// 结构体不定长数组
Person[] persons;
// 函数中可以往里面添加值,类型必须是结构体初始化对象
persons.push(p1);

2.2.4 mapping:映射,

无法判断是否存在某个key 不支持length

mapping(string=>string) map_data;
// 函数中赋值
map_data["name"] = "hallen";
//获取指定的key的值
string storage aa = map_data["name"];

2.2.5 storage和memory

storage:数据永远保存,引用传递,只有引用类型的变量才可以显示的声明为storage。

memory:存在内存中,会被回收,数据会过期丢失,类似值类型

bytes1、bytes、string相互转换

bytes1string要经过中间的bytes

角标用uint256类型,不然会类型不匹配

最后

小生凡一,期待你的关注。

在这里插入图片描述